【若川视野 x 源码共读】第21期 | await-to-js 如何优雅的捕获 await 的错误

56 阅读2分钟

git源码:github.com/scopsy/awai…

官网:blog.grossman.io/how-to-writ…

1、原因

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

1、promise:解决回调地狱,但是会使异步流变得更加复杂

function asyncTask(cb) {
  
  asyncFuncA.then(AsyncFuncB)
    .then(AsyncFuncC)
    .then(AsyncFuncD)
    .then(data => cb(null, data)
          .catch(err => cb(err));
}index.js

2、es7 aysnc/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);
}

2、但是如何处理错误 try/catch

1、重复try/catch使代码看上不干净

async function asyncTask(cb) {
  try {
    const user = await UserModel.findById(1);
    if(!user) return cb('No user found');
  } catch(e) {
    return cb('Unexpected error occurred');
  }
  
  try {
    const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
  } catch(e) {
    return cb('Error occurred while saving task');
  }
  
  if(user.notificationsEnabled) {
    try {
      await NotificationService.sendNotification(user.id, 'Task Created');  
    } catch(e) {
      return cb('Error while sending notification');
    }
  }
  
  if(savedTask.assignedUser.id !== user.id) {
    try {
      await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');
    } catch(e) {
      return cb('Error while sending notification');
    }
  }
  
  cb(null, savedTask);
}

2、await-to-js

export default function to(promise) {
  return promise.then(data => {
    return [null, data];
  })
    .catch(err => [err]);
}
//实用程序函数接收一个 promise,然后将成功响应解析为一个数组,
//并将返回数据作为第二项。从捕获接收的错误是第一个。

3、最终

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

3、源码

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

4、感谢

自己开发的时候 相对比较少的用到promise 总是觉得不顺少,所以每一次学习都加深印象,以后的问题是不是可以这样处理。总之冲 哈哈哈 然后很感谢若川老师 真的很厉害 每次都很感谢