源码阅读04- await-to-js

122 阅读2分钟

我正在参与掘金会员专属活动-源码共读第一期,点击参与

前言

刚开始接触 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

源码地址:github.com/scopsy/awai…

功能

从 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?