浅析async await错误处理问题及如何不使用try catch优雅地进行错误处理


一、Async 函数的错误处理

  async 函数的语法不难,难在错误处理上。先来看下面的例子:

  我们可以看到 Promise 报错后,a = await 1 并没有被执行。即当 async 函数中只要一个 await 出现 reject 状态,则后面的 await 都不会被执行。

  解决办法是:可以添加 try catch。

// 正确的写法
let a; async function correct() { try { await Promise.reject('error') } catch (error) { console.log(error); } a = await 1; return a; } correct().then(v => console.log(a));

  这样就会先打印 error,再打印 1。因此,如果有多个 await 则可以将其都放在 try/catch 中,但很显然,这样并不优雅。

// 我们需要对每一次异步操作进行错误处理
function async asyncTask(cb) { try { const asyncFuncARes = await asyncFuncA() } catch(error) { return new Error(error) } try { const asyncFuncBRes = await asyncFuncB(asyncFuncARes) } catch(error) { return new Error(error) } try { const asyncFuncCRes = await asyncFuncC(asyncFuncBRes) } catch(error) { return new Error(error) } }

二、npm包:await-to-js 及源码分析

  作者是这样介绍这个库的:Async await wrapper for easy error handling without try-catch。中文翻译过来就是:无需 try-catch 即可轻松处理错误的异步等待包装器。

  与上面对比,使用了await-to-js之后,我们可以这样的处理错误:

import to from './to.js'; function async asyncTask() { const [err, asyncFuncARes]  = await to(asyncFuncA()) if(err) throw new (error); const [err, asyncFuncBRes]  = await to(asyncFuncB(asyncFuncARes)) if(err) throw new (error); const [err, asyncFuncCRes]  = await to(asyncFuncC(asyncFuncBRes) if(err) throw new (error); }

  简洁多了,看看源码,没写想到只有 15 行,完全都可以自己作为一个公共方法使用即可。

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;

  上面是TS版的源码,但是考虑到有些同学可能还没接触过TS,我着重分析一下下面这版JS版的源码。

export function to(promise, errorExt) { return promise .then((data) => [null, data]) .catch((err) => {   if (errorExt) {   const parsedError = Object.assign({}, err, errorExt);   return [parsedError, undefined];   }    return [err, undefined];   }); } export default to;

  这里我们先抛开 errorExt 这个自定义的错误文本,可以看出:其代码的逻辑用中文解释是这样的:

  • 无论成功还是失败,都返回一个数组,数组的第一项是和错误相关的,数组的第二项是和响结果相关的
  • 成功的话,数组第一项也就是错误信息为空,数组第二项也就是响应结果正常返回
  • 失败的话,数组第一项也就是错误信息为错误信息,数组第二项也就是响应结果返回undefined

  经过上面的分析发现:其实挺简单的,但是,又确实挺巧妙的,我们也并不是做不到,而不是想不到。

  这里我们再来看函数 to 的第二个参数 errorExt,不难发现这其实就是拿来用户自定义错误信息的,通过 Object.assign 将正常返回的 error 和用户自定义的,合并到一个对象里面供用户自己选择。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM