【源码阅读】async/await的错误捕获

164 阅读2分钟

问题背景:

js异步逻辑的写法,最早是回调函数方式。回调函数方式,在逻辑复杂时,代码会不断嵌套,代码逻辑逐渐会变得难以阅读。

function AsyncTask() {
   asyncFuncA(function(err, resultA){
      if(err) return cb(err);

      asyncFuncB(function(err, resultB){
         if(err) return cb(err);

          asyncFuncC(function(err, resultC){
               if(err) return cb(err);

               // And so it goes....
          });
      });
   });
}

后来ES6中出现了Promise该方案使用链式调用的方式,解决了回调地狱的问题,使代码逻辑看起来更加清晰。

function asyncTask(cb) {

   asyncFuncA.then(AsyncFuncB)
      .then(AsyncFuncC)
      .then(AsyncFuncD)
      .then(data => cb(null, data)
      .catch(err => cb(err));
}

虽然Promise链式调用很好的解决了回调地狱的问题,但是在复杂的业务场景下,代码还是会存在冗余,因此ES7中发布了async/await语法,能够完全使用同步的方式去书写异步代码。

async function asyncTask(cb) {
    const user = await UserModel.findById(1);
    if(!user) return cb('No user found');

    const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
    
    if(user.notificationsEnabled) {
         await NotificationService.sendNotification(user.id, 'Task Created');  
    }

    if(savedTask.assignedUser.id !== user.id) {
        await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you')
    }

    cb(null, savedTask);
}

Promise处理错误是通过catch方法捕获错误,而async/await语法需要使用try/catch去捕获。在使用async/await每次都必须使用配合使用try/catch去进行错误捕获,这就有点恶心了。有没有什么其他的方法能避免这种情况呢?

await-to-js

这个库可以让你在使用await的时候,无需使用try-catch就能捕获错误。 他是怎么实现呢?

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];
    });
}

上面就是这个库的源码,很简单的方法。 这个库接受一个promise作为参数,将该promise包装一层,原先promise的返回值是data,包装后返回值是[err,data]。