Promises 使得可以简化异步流程并避免回调地狱。
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);
// do something....
});
});
});
}
async/await 使得可以以编写同步代码的方式处理异步代码。在 async/await 函数中,通常使用 try/catch 块来捕获错误,防止程序中断。
但是如果存在多个 async/await,而且需要分开处理错误,多个 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);
}
如何解决呢?
我们可以利用 Promise
的特性,分别在 promise.then
和 promise.catch
中返回不同的数组,其中 fulfilled
的时候返回数组第一项为结果,第二个是 null
。rejected
的时候,返回数组第一项为 null,第二项为错误信息。使用的时候,判断第二项是否为空,即可知道是否有错误。
/**
* @param { Promise } promise
* @param { Object= } errorExt - 传递给 err 对象的附加信息
* @return { Promise }
*/
function to<T, U = Error> (
promise: Promise<T>,
errorExt?: object
): Promise<[null, U] | [T, null]> {
return promise
.then<[T, null]>((data: T) => [data, null])
.catch<[null, U]>((err: U) => {
if (errorExt) {
const parsedError = { ...err, ...errorExt });
return [null, parsedError];
}
return [null, err];
});
}
或者可以在try...catch 中执行 promise ,以处理错误,最后将返回一个长度为2的数组,其中第一个是 response 或 result ,第二个则是 error。
async function asyncHandler<T, U = Error>(
prom: Promise<T>
): Promise<[T | null, U | null]> {
try {
return [await prom, null];
} catch (error) {
return [null, error];
}
}
/** 同步函数处理 */
function syncHandler<T extends any[], K, U = Error>(
func: (...args: T) => K,
...params: T
): [K | null, U | null] {
try {
return [func(...params), null];
} catch (error) {
return [null, error];
}
}