实用小工具,如何优雅地捕获async里的错误。

86 阅读1分钟

偶然在GitHub上看到的一个有趣的开源api。
作者将async里的promise进行包装再将错误包装避免大量实用try-catch语句。
GitHub地址

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

使用如下:

import to from 'await-to-js';
// If you use CommonJS (i.e NodeJS environment), it should be:
// const to = require('await-to-js').default;

async function asyncTaskWithCb(cb) {
     let err, user, savedTask, notification;

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

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

    if(user.notificationsEnabled) {
       [ err ] = await to(NotificationService.sendNotification(user.id, 'Task Created'));
       if(err) return cb('Error while sending notification');
    }

    if(savedTask.assignedUser.id !== user.id) {
       [ err, notification ] = await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'));
       if(err) return cb('Error while sending notification');
    }

    cb(null, savedTask);
}

async function asyncFunctionWithThrow() {
  const [err, user] = await to(UserModel.findById(1));
  if (!user) throw new Error('User not found');
  
}

简单来说就是接受await后面的promise然后再链式调用then和catch对错误进行包装。
执行成果返回[null,res]失败返回[err,null]。
一个小小的to可以避免很多async函数里面的try-catch。
这里用js小小更改适配了一下

const to = promise => {
    return promise
        .then(res => [true, res])
        .catch(err => {
            return [false, err]
        })
}