本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
这是源码共读的第21期,链接:juejin.cn/post/708310…
问题
在日常开发中,我们经常使用经常用async await来处理异步任务,如数据请求等。
function getUser() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
id: 1,
name: "张三"
});
}, 1000);
});
}
async function getData() {
try {
let data = await getUser();
console.log(data);
} catch (error) {
console.log(error);
}
}
getData();
对于async函数中出现的错误我们经常使用try catch捕捉,但是当其中业务逻辑很多的时候就会出现很多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);
}
可选的解决方案
使用await-to-js库可使代码变得更简洁。
import to from 'await-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');
}
}
分析源码
从源码中我们可以看出
await-to-js对传入的promise进一步处理,通过then方法返回处理成功的promise,成功的值为[null,data]。通过catch方法返回处理失败的promise,失败的返回值为[err,undefined]。然后在对to方法使用await时,使用数组解构出返回的结果来捕捉错误,这样就省去了使用try catch块捕捉错误。