asyncawait的错误处理⽅法
1. try/catch
es6 的初学者必须知道的捕获错误的⽅法,因为它是相对来说最保险的,既可以捕获同步错误也可以捕获异步错误。
捕获异步错误:
run();
await和async使用方法async function run(){
try{
ject(new Error('Oops!'));
}catch(error){
}
}
捕获同步错误:
run();
async function run(){
const v =null;
try{
solve('foo');
v.thisWillThrow;
}catch(error){
// "TypeError: Cannot read property 'thisWillThrow' of null"
}
}
新⼿⽤ async/await 容易犯的错误之⼀,是忘记捕获错误,这是⼤忌,它会导致出现“S级”的异常:**控制台既没有报错,期待的效果也没有work,会导致很难定位问题。**以下的⽰例取⾃于⼀个个⼈⽐较常见的情景:
import api from'./api.js'// 引⼊了⼀个请求库
run();
async function run(){
const res =('xxxx')
// 期待打印出请求结果,但因为没有做错误处理,
// 导致当⽹络请求出错时,这⼀⾏既没有⾛到,
// 控制台也没有抛出 Error,会很难定位问题
console.log(res)
}
但这不意味着 try/catch 就万⽆⼀失了。try 代码块中被 return 的 rejected 的 promise 是⽆法被捕获到的:
run();
async function run(){
try{
// 注意:这是⼀个 `return` ,不是 `await`
ject(new Error('Oops!'));
}catch(error){
// 不会运⾏
}
}
其实,将 return 改成 return await 可以解决这个问题的,但容易遗漏。
2. 以Golang 风格捕获错误
⽤ .then() 将 rejected 状态的 promise 转成成功状态的 promise 并返回错误,可以⽤ if (err) 来检查是否出错run();
async function throwAnError(){
throw new Error('Oops!');
}
async function noError(){
return42;
}
async function run(){
// `.then(() => null, err => err)` 模式下,
// 当错误发⽣时返回⼀个 error ,否则返回 null
let err =await throwAnError().then(()=>null, err => err);
if(err !=null){
}
err =await noError().then(()=>null, err => err);
err;// null
}
如果同时需要成功的值和错误信息,可以像写 Golang ⼀样写 Javascript。
run();
async function throwAnError(){
throw new Error('Oops!');
}
async function noError(){
return42;
}
async function run(){
// `.then(v => [null, v], err => [err, null])` 的模式
// 让你能⽤数组的形式同时获取 error 和 result
let[err, res]=await throwAnError().
then(v =>[null, v], err =>[err,null]);
if(err !=null){
}
[err, res]=await noError().
then(v =>[null, v], err =>[err,null]);
err;// null
res;// 42
}
如果喜欢这种写法,还可以对它做⼀个封装:
export default function to(promise){
return promise.then(data =>{
return[null, data];
})
.catch(err =>[err]);
}
// use
import to from'./to.js';
run();
async function throwAnError(){
throw new Error('Oops!');
}
async function noError(){
return42;
}
async function run(){
// ⽤ to 来曝光promise
let[err, res]=await to(throwAnError())
if(err !=null){
}
[err, res]=await to(noError())
err;// null
res;// 42
}
如果需要拓展 error 的信息、是否 errorFirst,甚⾄可以做更复杂的封装:
// to.js
function to(promise, errorProps ={}, errorFirst =true){
return promise.then((data)=> errorFirst ?[null, data]:[data,null])
.catch(err =>{
if(errorProps) Object.assign(err, errorProps)
errorFirst ?[err,null]:[null, err]
})
}
3. catch()
try/catch 和 Golang风格的错误处理都有它们的⽤途,但是,要确保你处理了 run() 函数⾥所有错误的、最好的⽅法,是⽤
run().catch()(前提:run是异步函数)。换句话说,在调⽤函数时就处理错误,⽽不是单独处理每个错误。
run().
catch(function handleError(err){
}).
// 处理 `handleError()`中的任何错误:如果出错则杀死进程
catch(err =>{ Tick(()=>{throw err;})});
async function run(){
ject(new Error('Oops!'));
}
记住,所有的 async 函数总是返回 promises。如果函数内有任何未捕获的错误发⽣了,这个 promise 也会 rejected。如果你的 async 函数返回了⼀个 rejected 的 promise,返回的 promise 也会 rejected 。
catch(function handleError(err){
}).
// 处理 `handleError()`中的任何错误:如果出错则杀死进程
catch(err =>{ Tick(()=>{throw err;})});
async function run(){
// 注意:这是⼀个 `return` ,不是 `await`
ject(new Error('Oops!'));
}
总结
try/catch Golang风格.catch()
优点- 最保险的,可捕获同步、await的异步错误
- 流程控制准确
- 优雅
- 能捕获异步函数体内的同步和抛出的异步
错误
缺点- ⽆法捕获 try块中,被return 的异步错误(可
⽤return await解决)
- 不能优雅地对错误分别处理
-
不适⽤于流程中不需要中断的错误
- ⽆法避免catch本⾝抛出异常且不好处理
- ⼤量重复 if(err !== null),可能遗漏
- ⽆法捕获外部函数体内的同步错误
- 只适⽤于有 .catch() ⽅法的异步函数
场景⾮常适合简单流程、不希望出错后影响后续执⾏流程
的情景
适合链路长、较复杂的异步流程;适合于单个环
节出错不影响流程
适合处理期望外的错误,及时处理;适合
给.catch() 做兜底
参考资料

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。