async/await 函数到底要不要加 try catch ?

简介: async/await 函数到底要不要加 try catch ?

前言


写异步函数的时候,promise 和 async 两种方案都非常常见,甚至同一个项目里,不同的开发人员都使用不同的习惯, 不过关于两者的比较不是本文关注的重点,只总结为一句话:“async 是异步编程的终极解决方案”。

当使用 async 函数的时候,很多文章都说建议用 try catch 来捕获异常, 可是实际上我看了很多项目的代码,遵循的并不是严谨,很多都没有用,甚至 catch 函数都没写,这是为什么呢?

我们先看下使用 try catch 情况下的代码示例:


示例1 :使用 try catch


function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
                reject('请求异常')
        }, 1000)
    })
}
async function logined () {
    try {
        let userInfo = await getUserInfo()
        // 执行中断
        let pageInfo = await getPageInfo(userInfo?.userId)
    } catch(e) {
        console.warn(e)
    }
}
logined()


执行后会在 catch 里捕获 请求异常,然后 getUserInfo 函数中断执行,这是符合逻辑的,对于有依赖关系的接口,中断执行可以避免程序崩溃,这里唯一的问题是 try catch 貌似占据了太多行数,如果每个接口都写的话看起来略显冗余。


示例2: 直接 catch


鉴于正常情况下,await 命令后面是一个 Promise 对象, 所以上面代码可以很自然的想到优化方案:


function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
                reject('请求异常')
        }, 1000)
    })
}
async function logined () {
    let userInfo = await getUserInfo().catch(e => console.warn(e))
    // 执行没有中断,userInfo 为 undefined
    if (!userInfo) return // 需要做非空校验
    let pageInfo = await getPageInfo(userInfo?.userId)
}
logined()


执行后 catch 可以正常捕获异常,但是程序没有中断,返回值 userInfoundefined, 所以如果这样写的话,就需要对返回值进行非空校验,  if (!userInfo) return 我觉得这样有点反逻辑,异常时就应该中断执行才对;


示例3:在 catch  里 reject


可以继续优化,在 catch 里面加一行 return Promise.reject(e), 可以使 await 中断执行;

完整代码:


function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('请求异常')
        }, 1000)
    })
}
async function logined () {
    let userInfo = await getUserInfo().catch(e => {
        console.warn(e)
        return Promise.reject(e) // 会导致控制台出现 uncaught (in promise) 报错信息
    })
    // 执行中断
    let pageInfo = await getPageInfo(userInfo?.userId)
}
logined()


一般我们在项目里都是用 axios 或者 fetch 之类发送请求,会对其进行一个封装,也可以在里面进行 catch 操作,对错误信息先一步处理,至于是否需要 reject,就看你是否想要在 await 命令异常时候中断了;不使用 reject 则不会中断,但是需要每个接口拿到 response 后先 非空校验, 使用 reject 则会在异常处中断,并且会在控制台暴露  uncaught (in promise)  报错信息。


1687783648742.png


建议


不需要在 await 处异常时中断,可以这样写,需要做非空校验,控制台不会有报错信息


let userInfo = await getUserInfo().catch(e => console.warn(e))
if (!userInfo) return


需要在 await 处异常时中断,并且在意控制台报错,可以这样写


try {
    let userInfo = await getUserInfo()
    // 执行中断
    let pageInfo = await getPageInfo(userInfo?.userId)
} catch(e) {
    console.warn(e)
}


需要在 await 处异常时中断,但是不在意控制台报错,则可以这样写


let userInfo = await getUserInfo().catch(e => {
    console.warn(e)
    return Promise.reject(e) // 会导致控制台出现 uncaught (in promise) 报错信息
})
// 执行中断
let pageInfo = await getPageInfo(userInfo?.userId)


总结


几种写法,初看可能觉得第三种 catch 这种写法是最好的,但是细想下,从用户体验上来看,我觉得 try catch 是最好的,逻辑直观、符合同步编程思维,控制台不会暴露 uncaught (in promise) 报错信息;

而链式调用的 catch (里面再 reject),是传统 promise 的回调写法,既然已经用 async await 这种同步编程写法了,再用 catch 链式写法,感觉没必要。

目录
相关文章
|
6月前
|
数据采集 传感器 算法
从数据中挖掘洞见:初探数据挖掘的艺术与科学
从数据中挖掘洞见:初探数据挖掘的艺术与科学
141 11
|
9月前
|
传感器 机器学习/深度学习 人工智能
AI在自动驾驶汽车中的应用与未来展望
AI在自动驾驶汽车中的应用与未来展望
480 9
|
人工智能
Adam有了mini版:内存占用少一半,吞吐量提升50%
【7月更文挑战第18天】研究人员推出Adam-mini,针对AdamW的轻量化版本,旨在降低内存占用并提升训练大型模型的效率。通过参数分块和共享学习率,Adam-mini在70亿参数模型上实现50%内存节省,同时提高训练吞吐量50%,加速训练过程。然而,仍需考虑计算开销、通信成本及适用性问题。论文链接:[arxiv.org/pdf/2406.16793](https://arxiv.org/pdf/2406.16793)
179 3
|
11月前
|
人工智能 自然语言处理 机器人
“今日热点:AI像人类一样使用手机和电脑”,魔搭社区的开源项目已先行一步
今天,Claude发布了Computer Use的新功能,可以让AI像人一样使用电脑!
|
10月前
|
算法 网络协议 网络安全
政务单位免费IP地址SSL证书
政务单位申请免费IP地址SSL证书需先确认IP地址为公网IP并拥有管理权限,选择如JoySSL等提供免费测试证书的服务商。申请流程包括注册账号、选择证书类型、提交申请、验证信息、等待审核签发、下载安装证书。注意事项包括安全性、合规性、定期更新及技术支持。通过合理配置,可提升网站安全性和公信力。
|
前端开发 JavaScript 小程序
【JS】async、await异常捕获,这样做才完美
本文通过生动的例子说明了在JavaScript中使用async/await时,不捕获异常可能导致的问题,并介绍了三种处理异步调用异常的方法:try-catch、使用Promise的`.catch`以及`await-to-js`插件库。通过这些方法,可以有效避免异常导致的程序中断,提升代码的健壮性和可读性。
223 0
【JS】async、await异常捕获,这样做才完美
|
人工智能 弹性计算 并行计算
【Hello AI】推理引擎DeepGPU-LLM-提供免费的高性能、低延迟推理服务
DeepGPU-LLM是阿里云研发的基于GPU云服务器的大语言模型(Large Language Model,LLM)推理引擎,在处理大语言模型任务中,该推理引擎可以为您提供高性能的大模型推理服务。
|
SQL 关系型数据库 HIVE
KLOOK客路旅行基于Apache Hudi的数据湖实践
KLOOK客路旅行基于Apache Hudi的数据湖实践
268 2
KLOOK客路旅行基于Apache Hudi的数据湖实践
|
缓存 NoSQL Java
一次访问Redis延时高问题排查与总结
作者抽丝剥茧的记录了一次访问Redis延时高问题的排查和总结。
|
索引
Elasticsearch exception [type=illegal_argument_exception, reason=index [.1] is the write index for data stream [slowlog] and cannot be deleted]
在 Elasticsearch 中,你尝试删除的索引是一个数据流(data stream)的一部分,而且是数据流的写入索引(write index),因此无法直接删除它。为了解决这个问题,你可以按照以下步骤进行操作:
1139 0