await-to-js 源码学习

203 阅读2分钟

前言

在async/await中如何优雅的处理try/catch问题

async/await优点

相信大家对async/await都比较熟悉了,作为目前js异步编程“终极”解决方案,相比较于 Promise.then 的写法,在忽略关键字 async/await 的情况下,相当于用同步的代码风格来写异步的实现,让开发人员彻底摆脱了回调地狱。

Promise用法

    function () todo() {console.log('todo')}
    Promise.resolve().then(todo).then(todo)

async/await用法

    function () todo() {console.log('todo')}
    async function () {
        await Promise.resolve()
        todo()
        todo()
    }

不太完美的地方

如果程序需要捕捉错误那么书写起来还是不太令人满意

async function async(cb) {
    try {
        await do();
    } catch(e) {
        return cb('catch error');
    }
}

可以看到需要写try/catch语句,而且如果有多个地方需到捕捉异常则需要写多个try/catch语句,相当于回到解放前。这里就来看看 await-to-js 是如何处理的

源码分析

/**
 * @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;

可以看到 await-to-js 是通过设定promise.thenpromise.catch固定返回数组的方式来把错误和数据返回,其中数组第一项固定为promise.catch捕获的错误,数组第二项固定为promise.then返回的数据,而根据promise的特性,这两个数据不会同时存在,所以只要判断下数据是否存在即可知道是否有异常。

使用

import to from './to.js';

async function asyncTask() {
     let err, user, savedTask;

     [err, user] = await to(UserModel.findById(1));
     if(!user) throw new CustomerError('No user found');

     [err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
     if(err) throw new CustomError('Error occurred while saving task');

    if(user.notificationsEnabled) {
       const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created'));  
       if (err) console.error('Just log the error and continue flow');
    }
}

可以看到我们又可以愉快的使用同步的方式书写代码而不需要写一大堆try/catch