我正在参与掘金会员专属活动-源码共读第一期,点击参与
前言
刚开始接触 Node 开发的时候,基本都是全部 callback 完成所有的业务逻辑开发。看整个项目代码时经常会被这个层层的 callback 给绕晕了。后来使用了 promise 优化了 callback 的结构,但又引发新的问题,那就是会产生一个很长的 then 链路,且其他问题。
async/await
ES7 的新特性 async/await 是真的拯救了异步。它可以像同步那样去使用异步。
async function DoTask(id){
const user = await User.findById(id)
....
}
这样就跟你写同步顺序一样,但是还是会存在问题:如果一段业务处理有很多异步的过程,那么在异常处理时,可能就需要比较多个 try catch 去捕获每个异常。代码看起来很不友好,而且出现错误就会退出函数,
async function DoTask(id){
try{
const user = await User.findById(id)
}catch(err){}
....
try{
const department = await department.findById(id)
}catch(err){}
}
await-to-js 的出现就是为了优雅的解决 try-catch 的问题。
await-to-js
功能
从 git 仓库中提供的 demo 可以看到 awiat-to-js 的可以让你的异步逻辑更健壮。
import to from 'await-to-js';
[ err, user ] = await to(UserModel.findById(1));
使用 await-to-js 可以直接返回一个 err 和结果集。这个过程像 Golang 语法一样,支持多个返回结果。如果方法返回成功的话,就有2个结果,第一个是 err 结果,因为是成功的 err=null,第二个是真正的返回结果值。如果方法返回失败的则,err 就会值。
源码分析
/**
* @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;
源码是使用typescript写,也比较简单。 一个 to 函数,接收2个参数:
- 第一个参数是一个 promise
- 第二个参数是一个可选错误信息对象
函数里面其实就是对 promise 的执行。then 中[null, data] 就是最后成功的返回值。catch 中还会判断下是否有额外的错误对象,如果有就会合并异常和错误对象,然后返回[err, undefined]。没有的话直接将 promise 返回的异常进行返回。
所以,其实整个过程其实就是对 promise 进行了一层封装。成功返回[null, data], 失败返回[err, undefined]。其中err 如果你传递自定义的错误对象,那么就会和 promise 产生的异常进行合并否则err 就只是 promise 产生的异常。
但是对以上的源码,我有个疑问点:失败的时候虽然 data 不会有用到,但是为什么值设置为 undefined,而不是 null?