- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第21期,链接:juejin.cn/post/708310…
await-to-js作用:
是async、await包装器,便于处理错误
Callback 回调函数处理异步
function AsyncTask(cb){
asyncFunA(function(err, resultA){
if(err) return cb(err)
asyncFunB(function(err, resultB){
if(err) return cb(err)
asyncFunC(function, resultC){
if(err) return cb(err)
...
})
})
})
}
我们之前处理异步的方法就像上面的一样,像俄罗斯套娃一样,一层一层,造成了回调地狱。后面我们就有的 Promise。
Promise 异步函数 Promise 是 ES6 提供的方法,目的是解决回调地狱,更优雅的处理复杂的异步任务。 Promise 将之前的回调地狱,改成了链式调用的形式。
function AsyncTask(cb){
asyncFuncA.then(AsyncFuncB)
.then(AsyncFuncC)
.then(AsyncFuncD)
.then(data => cb(null, data)
.catch(err => cb(err))
}
Promise.all 方法,也支持多个并发请求,获取并发请求中的数据。 但是 promise 也有美中不足的地方:
- 不够同步
- 不能很方便的给每一次异步操作进行处理
那么async/await 能够解决:
function async asyncTask(cb) {
const asyncFuncARes = await asyncFuncA()
const asyncFuncBRes = await asyncFuncB(asyncFuncARes)
const asyncFuncCRes = await asyncFuncC(asyncFuncBRes)
}
异步调用时,由于异步函数等待 Promise,当 Promise 遇到错误,就会抛出一个异常,并在最后被 Promise 对象的 catch 方法捕获,使用 async 和 await ,就需要加上 try catch 来捕获错误,如下:
function async asyncTask(cb){
try {
const asyncFuncARes = await asyncFuncA()
} catch(error) {
return newError(error)
}
try {
const asyncFuncBRes = await asyncFuncB(asyncFuncARes)
} catch(error) {
return newError(error)
}
try {
const asyncFuncCRes = await asyncFuncC(asyncFuncBRes)
} catch(error) {
return newError(error)
}
}
但是为每一个 await 都添加 try/catch 显得有点臃肿,那么简化就需要用到 await-to-js 了。
await-to-js 源码
export function to(promise, errorExt){
return promise
.then((data) => [null, data]) // 成功,返回 [null, 响应结果]
.catch((err) => {
if(errorExt) {
const parseError = Object.assign({}, err, errorExt)
return [parsedError, undefined] // 失败,返回 [错误信息, undefined]
}
return [err, undefined]
})
}
export default to;
源码分析:
接收一个 promise, 将结果解析为一个数组,第一项存入 promise 的异常错误,第二项存入返回的数据。 传入的参数: 第一个是 promise 对象,第二个是可选的错误信息 to 方法会直接返回传入的 promise 的执行 在 then 中返回 [null, data]。null 是执行成功的返回, data 是最终的数据 在 catch 中, 先判断是否传入了额外的错误对象,存在的话,利用 Object.assign 将传入的错误对象与 promise 返回的异常进行合并,然后返回 [prasedError, undefined];不传入额外的错误对象,则直接返回 promise 的异常 [err, undefined]
案例:
async function asyncTask(userId, cb) {
let err, user, savedTask, notification;
[ err, user ] = await to(UserModel.findById(userId));
if(!(user && user.id)) return cb('No user found');
}
总结:
在使用 async 时,需要手动使用 try...catch.. 来捕获错误。而 await-to-js 直接将错误信息返回给用户。to 函数接收两个参数 promise 和 errorExt。 promise 参数接收一个 Promise 对象, 而errorExt 是可选的。Promise对对象,又定义了 then 和 catch 函数,无论成功失败都会返回一个数组。成功(then)时返回 [null, data] data 为成功时的响应结果。失败(catch)时返回[err, undefined]。当 errorExt存在时,返回[parsedError, undefined] , parsedError 是默认错误信息+用户自定义的错误信息。