背景
扫视一遍手里几千行还没被cr的代码,try-catch满屏都是,散落在💩山的角角落落并为之锦上添花!窥视前辈的代码,而是使用了await-to-js
提供的to
方法这种方式来处理错误,于是对await-to-js
心生好奇,并顺便梳理一下js的异步痛点与解决方案,这块虽比较基础,但简单说一说更加流畅一点,对新手更加友好,title都标注好了,大家跳到需要的地方看即可。
js异步痛点
前置理解------js异步
js代码一行接着一行按顺序执行的是同步代码,而需要等待某些条件实现时才触发的代码逻辑是异步代码(异步代码无法预测其执行顺序)。换句话说,同步或者异步代码只是js代码的两种分类,他们有着执行时机上的区别。
保证异步执行顺序------回调地狱
类比js编码,如果我们要实现的功能点是做饭,那么总共分为三个有顺序的步骤:买菜、洗菜最后是炒菜。而且这三个有先后顺序的步骤并不是同步js代码,而是异步代码,那么我们要保证买菜=>洗菜=>炒菜的顺序,就需要进行如下编码:
js
async function 买菜() {
// 处理买菜ing,得到了菜(洗菜需要)
洗菜();
}
async function 洗菜() {
// 处理洗菜ing,得到干净的菜(炒菜需要)
炒菜();
}
async function 炒菜() {
// 处理炒菜ing
}
// 开始买菜
买菜();
如上代码表达的就是买菜逻辑完成后才触发洗菜的逻辑,洗菜处理完后触发炒菜,等价于:
javascript
(async function 买菜() {
// 处理买菜ing,得到了菜(洗菜需要)
(async function 洗菜() {
// 处理洗菜ing,得到干净的菜(炒菜需要)
(async function 炒菜() {
// 处理炒菜ing
})();
})();
})();
说白了,如上嵌套的唯一目的就是保证异步逻辑之间的执行顺序,为了让洗菜滞后与买菜执行,那么我们编程实现的方式就是在买菜的函数体中定义并执行洗菜(逻辑上嵌套起来了,代码外观上一堆缩进,就是所谓的回调地狱/嵌套地狱)
es6提供的异步嵌套解决方案------promise
使用promise改写如上代码:
js
买菜()
.then((菜) => 洗菜)
.then((干净的菜) => 炒菜)
不嵌套了~
进一步优化------async语法糖
一直写.then堆成一长串,肯定不美观,而且炒菜逻辑中无法拿到刚买来的菜(只能拿到干净的菜)。使用async
改写如上逻辑:
js
async 买菜() {
const 干净的菜 = await 洗菜(菜);
const 饭 = await 炒菜(干净的菜); // 也可以 炒菜(菜)
return 饭;
}
买菜();
异步错误处理
try-catch
如果async函数中某些逻辑抱错,那么可以被其(出错逻辑)外层的try-catch
捕获,对
js
async 买菜() {
const 干净的菜 = await 洗菜(菜);
const 饭 = await 炒菜(干净的菜); // 也可以 炒菜(菜)
return 饭;
}
买菜();
进行改写:
js
async 买菜() {
try {
const 干净的菜 = await 洗菜(菜);
return 饭;
} catch (error) {
console.log('处理洗菜错误');
}
try {
const 饭 = await 炒菜(干净的菜);
} catch (error) {
console.log('处理炒菜错误');
}
return 饭;
}
买菜();
await-to-js
说实话由如上的try-catch示例引出await-to-js我认为并非必要,前者也并没有绝对的后者解决掉的痛点, 所以await-to-js的意义需要大家自己来品味,最后我也会说说我的理解。
上方代码改写:
js
async 买菜() {
const [error1, 干净的菜] = await to(洗菜(菜));
if(error1) {
console.log('处理洗菜错误');
}
const [error2, 饭] = await to(炒菜(干净的菜));
if (error2) {
console.log('处理炒菜错误');
}
return 饭;
}
买菜();
try-catch VS await-to-js------我的理解
如上所说:"说实话由如上的try-catch示例引出await-to-js我认为并非必要,前者也并没有绝对的后者解决掉的痛点, 所以await-to-js的意义需要大家自己来品味。"
try-catch优点
- try-catch可以捕获try作用域块里的所有错误,捕获范围更加灵活
try-catch缺点
- 丑陋?(我猜的!)
await-to-js优点
- 只捕获作为to方法参数的promise的错误,捕获更加精确
- 通过数组解构拿到res与error,代码更加易读
await-to-js缺点
- 需要引个包?(真编不出来了!)
await-to-js源码实现
删繁就简,丐版核心:
js
export default function to(promise) {
return promise.then(data => {
return [null, data];
})
.catch(err => [err, undefined]);
}
(给接收的promise添加了then和catch,成功就返回data,失败就返回err,返回的格式通过数组进行统一)