likes
comments
collection
share

【源码阅读】听说你还在单独为 await 做 try catch?要不进来瞅瞅?

作者站长头像
站长
· 阅读数 46

异步请求的历史演变

早期异步解决方案大哥大: callback

早期异步就是通过一层嵌套一层来解决的,简单粗暴,一个异步回来了之后在该异步回调里再调用另一个异步函数,然后在回调里再调用另一个异步函数... 巴拉巴拉 一大堆嵌套就形成了回调地狱。 这种方式代码阅读起来比较困难,也给可维护性带来了一定的困难。

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);

               // And so it goes....
          });
      });
   });
}

callback 的优化: Promise

在 ES6 的时候推出了 Promise,通过它可以对 callback 的回调地狱进行优化。

function asyncTask(cb) {
   asyncFuncA.then(AsyncFuncB)
      .then(AsyncFuncC)
      .then(AsyncFuncD)
      .then(data => cb(null, data)
      .catch(err => cb(err));
}

这个样子看上去就好多了,但是异步多了之后,这 .then 也需要写不少。 好!优化它!

升级 Promise,以同步的方式写异步: async await

在 ES7 的时候又推出了 async await。好好~。

async function asyncFun() {
  const result1 = await Promise1();
  const result2 = await Promise2();
  const result3 = await Promise3();
  ...
  const resultn = await Promisen();
  ...
}

通过查资料可以知道这只是 Generator 函数 + yield 的语法糖,具体可以看ECMAScript 6 入门教程。 这样来写异步就很舒服嘛~ 但是这样每写一个 await 就需要写一对 try catch。哇!痛苦! 接下来就该今天的主角 await-to-js 登场了~

介绍

源码地址: await-to-js

作者对该库的定义是: Async await wrapper for easy error handling. 那么它的用途也是用来解决在日常开发中使用 async + await 捕获错误时需要频繁定义 try catch 的问题。 现在就来看看它是怎么用的把~

用法

import to from 'await-to-js';

const [ err, res ] = await to(somePromise({userId: 'demoId', name: 'demoName'}));  

if (err) return console.error(err)
console.info(res)

它的用法也很简单,将业务上的请求传进去,然后会返回报错信息和结果,这里就省去了自己定义 try catch。 那么它是怎么实现的呢?瞅瞅去~

源码分析

库的目录结构很简单,源码实现的位置 也很好找。

/**  
 * @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;

通过源码可以看到:

  1. 它接收两个参数:一个是必传的业务上 Promise 实例;一个是可选的额外错误信息。
  2. 它的返回值永远是一个 Promise,其泛型是一个 length 为 2 的数组,第一项是错误信息、第二项是请求结果。
  3. 内部实现是通过调用传入的 Promise 实例,在 thencatch 中分别处理成功和失败最后将其结果放到数组并返回。在处理错误的时候如果有传入第二个参数则将其和错误信息通过 Object.assign() 合并后放到数组中返回。 最终知道该库其实就是将 Promisethencatch 封装了一下,然后统一返回(哈哈哈哈哈哈~)。

总结

  • 库的源码并不多,但是这个封装可以应用到项目中去,这样就不需要每次都手动 try catch
  • 这篇小源码就当做是重启学习的标志吧~哈哈哈哈哈。
转载自:https://juejin.cn/post/7203993298817990716
评论
请登录