async_await异常捕获

写在前面

不知道大家项目里面是怎么处理 async/await 的异常,我斗胆在我们项目里翻了一下,发现大量使用 try-catch 来处理 async/await 异常。

try-awati-catch.png

首先说明一下, try-catch 处理并没有什么问题,我只是觉得这么写代码会有点乱,感觉代码逻辑像是断层了一样,不易理解;

其次是代码冗余问题,单个 try-catch 就占了好几行代码,如果每个请求的地方都添加 try-catch,就会显得代码很臃肿。
而对于这种大量相同的冗余代码,完全可以用一种通用的函数来替代。

async/await 是在 ES2017 中引入的,目的是为了让异步操作更加直观、方便,同时也解决了 Promise 的回调地狱问题。想必这些概念大家都已经了解了,那么我们为什么要捕获 async/await 的异常呢?它们是在什么时候发生异常呢? 带着问题我们一起看一下本文。

什么时候会请求异常

我们都知道 await 后面一般都是异步请求,异步请求发生异常的原因大致有以下几种:

  1. 网络问题导致,网络断开连接,请求不到;
  2. 网络慢导致异步请求超时。

什么情况下需要处理请求异常

一旦有以上情况出现,这个异步请求就会产生异常,而 JavaScript 又是一个单线程语言,代码报错后就会导致后面的代码无法继续执行,所以此时就需要添加 try-catch 来捕获异步请求的异常,使得代码可以继续向后执行。

但有必要为所有的异步请求都加 try-catch 吗?

我研究了下我们项目的代码,异步请求加了 try-catch 处理的,有以下几种情况:

多个异步请求串行

try {
  // 获取列表list
  const list = await getList(params)
  // 获取单个详情
  const info = await getListById(list[0]?.id)
} catch {}

前一个异步请求的返回结果,会作为后一个异步请求的请求参数使用,所以一旦前一个请求异常,后面的请求肯定会异常,所以需要添加 try-catch 处理。

处理异步请求的 loading 状态

loading.value = true
try {
  // 获取列表list
  const list = await getList(params)
} finally {
  loading.value = false
}

一般我们处理异步请求前,会为其添加 loading 状态,而一旦请求异常出现时,如果不加 try-catch 时就会导致页面一直处于 loading 状态。所以需要在finally中将 loading 状态置为 false,catch中处理时需要外部再处理一次

那么,我们如何优雅的处理异步请求中的 try-catch 呢?

处理方法

使用 Promise 处理

首先需要明确一点:正常情况下,await 命令后面是一个 Promise 对象。所以它本身就可以使用.catch来捕获异常,那么像上面第二种只是处理 loading 状态的操作,完全可以在.catch进行处理,然后用if判断来控制提前退出,没必要写 try-catch 这种冗余代码。

loading.value = true
let res = await getList().catch(() => (loading.value = false))
if (!res) return
// 请求成功后正常操作

await-to-js 处理函数

简单的异步请求我们可以使用上面这种方法,但遇到多个异步操作时,就需要借助我们今天要说的await-to-js这个库,它的介绍很简单:无需 try-catch 即可轻松处理错误

而且源码贼简单,就 23 行代码,我们一起来看看。

/**
 * @param { Promise } promise
 * @param { Object= } errorExt - Additional Information you can pass to the err object
 * @return { Promise }
 */
export function to<T, U = Error>(
  promise: Promise<T>,
  errorExt?: object
): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>((err: U) => {
      if (errorExt) {
        const parsedError = Object.assign({}, err, errorExt)
        return [parsedError, undefined]
      }

      return [err, undefined]
    })
}

export default to

大致流程如下:
函数to接受参数PromiseerrorExt,如果这个 Promise 成功时返回[null, data],如果异常时会判断是否带有errorExt参数(代表传递给 err 对象的附加信息),如果有时会与 catch 捕获的 err 合并返回,如果没有时返回[err, undefined]

很简单的逻辑是不是,接着我们看下它的用法:

  • 安装

    # use npm
    npm i await-to-js --save
    # use yarn
    yarn add await-to-js
    
  • 使用

    首先引入to函数,可以看到包很小,只有 370b,gzip 压缩后只有 242b,所以放心引入,别担心什么包大小问题。

    await-to-js-size.png

    我们通过to来改写一下上面第一种问题:

    import to from 'await-to-js'
    
    // 获取列表list
    const [err, data] = await to(getList(params))
    if (err) return
    // 获取单个详情
    const info = await to(getListById(list[0]?.id))
    

    通过to函数改造后,如果返回第一个参数不为空时,说明该请求报错,就可以提前 return 出去,如果不存在第一个参数时,则异步请求成功。

总结

本文通过研究 async/await 的异常捕获,发现了两种常见的异步请求异常捕获,并提出了两种简单的解决方法。通过这两种方法,就可以丢掉冗余的 try-catch,然后你就会发现没了 try-catch 的代码看起来都是顺眼的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用async/await捕获异常有几种方法。首先,可以在async函数内部使用try-catch语句块来捕获异常。当遇到可能抛出异常的代码块时,可以将其放在try块中,然后使用catch块来捕获异常并进行相应处理。例如: ``` async function myFunction() { try { // 异步操作 await someAsyncOperation(); } catch (error) { // 异常处理 console.log(error); } } ``` 另外一种方法是使用catch方法。在async函数中,可以在使用await关键字的时候链式调用catch方法来捕获异常。这样可以将错误处理逻辑分离出来,使代码更加简洁。例如: ``` async function myFunction() { await someAsyncOperation().catch(error => { // 异常处理 console.log(error); }); } ``` 需要注意的是,无论是try-catch语句还是catch方法,都可以捕获async函数内部的异常。但如果在await之外的代码块中出现异常,需要在调用async函数的地方使用try-catch语句来捕获异常。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [async 与 await 是啥?如何捕获异常?](https://blog.csdn.net/qq_36437172/article/details/109440296)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [async/await错误捕获](https://blog.csdn.net/qq_39970857/article/details/116979564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端鼓励师

老铁 支持一波

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值