【源码阅读】听说你还在单独为 await 做 try catch?要不进来瞅瞅?
- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第21期,链接:【若川视野 x 源码共读】第21期 | await-to-js 如何优雅的捕获 await 的错误。
异步请求的历史演变
早期异步解决方案大哥大: 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;
通过源码可以看到:
- 它接收两个参数:一个是必传的业务上
Promise
实例;一个是可选的额外错误信息。 - 它的返回值永远是一个
Promise
,其泛型是一个length
为 2 的数组,第一项是错误信息、第二项是请求结果。 - 内部实现是通过调用传入的
Promise
实例,在then
和catch
中分别处理成功和失败最后将其结果放到数组并返回。在处理错误的时候如果有传入第二个参数则将其和错误信息通过Object.assign()
合并后放到数组中返回。 最终知道该库其实就是将Promise
的then
和catch
封装了一下,然后统一返回(哈哈哈哈哈哈~)。
总结
- 库的源码并不多,但是这个封装可以应用到项目中去,这样就不需要每次都手动
try catch
。 - 这篇小源码就当做是重启学习的标志吧~哈哈哈哈哈。
转载自:https://juejin.cn/post/7203993298817990716