- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第21期,链接:【若川视野 x 源码共读】第21期 | await-to-js 如何优雅的捕获 await 的错误。
问题背景:
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]。