译者按: 使用.catch()
来捕获全部的异常javascript
本文采用意译,版权归原做者全部html
async/await 中的异常处理很让人混乱。尽管有不少种方式来应对async 函数的异常,可是连经验丰富的开发者有时候也会搞错。java
假设你有一个叫作run()
的异步函数。在本文中,我会描述 3 种方式来处理run()
的异常情形: try/catch
, Go 语言风格, 函数调用的时候使用 catch()
(即run().catch()
)。 我会跟你解释为何其实几乎只须要catch()
就足够。node
try/catch
当你第一次使用async/await
, 你可能尝试使用try/catch
将每个 async 操做包围起来。若是你await
一个被 reject 的 Promise,JavaScript 会抛出一个能够被捕获的错误。golang
run();
async function run() {
try {
await Promise.reject(new Error("Oops!"));
} catch (error) {
error.message; // "Oops!"
}
}
复制代码
try/catch
可以捕获非异步的异常。编程
run();
async function run() {
const v = null;
try {
await Promise.resolve("foo");
v.thisWillThrow;
} catch (error) {
// "TypeError: Cannot read property 'thisWillThrow' of null"
error.message;
}
}
复制代码
因此,只须要将全部的代码逻辑都用 try/catch
包围起来就能够搞定?也不彻底正确。下面的代码会抛出unhandled promise rejection. await
将一个被拒绝的 promise 转换为可捕获的错误,可是 return
不行。小程序
run();
async function run() {
try {
// 注意这里是return,不是await
return Promise.reject(new Error("Oops!"));
} catch (error) {
// 代码不会执行到这里
}
}
复制代码
也不可能使用 return await
来绕开。微信小程序
还有一个缺点就是使用了try/catch
以后,就很难用.
的语法来进行 Promise 链式组合了。数组
另外一个常见的方式就是使用then()
将一个原本须要用catch()
来捕获并处理的 Promise 转换为普通的 Promise。而后像 Go 语言中同样,使用if(err)
来处理异常。promise
run();
async function throwAnError() {
throw new Error("Oops!");
}
async function noError() {
return 42;
}
async function run() {
// The `.then(() => null, err => err)` 来匹配正常/异常的状况。若是正常状况,返回`null`;若是异常,返回`err`
let err = await throwAnError().then(() => null, err => err);
if (err != null) {
err.message; // 'Oops'
}
err = await noError().then(() => null, err => err);
err; // null
}
复制代码
若是你真的想要同时返回 error 和正确的值,你能够彻底伪装在用 Go 语言。
run();
async function throwAnError() {
throw new Error("Oops!");
}
async function noError() {
return 42;
}
async function run() {
// The `.then(v => [null, v], err => [err, null])` pattern
// 你能够使用数组解构来匹配err和返回值
let [err, res] = await throwAnError().then(
v => [null, v],
err => [err, null]
);
if (err != null) {
err.message; // 'Oops'
}
err = await noError().then(v => [null, v], err => [err, null]);
err; // null
res; // 42
}
复制代码
使用 Go 语言风格的错误处理并不能摆脱return
没法捕获的状况。并且还让整个代码更加的复杂,若是忘记if(err != null)
,就会出问题。
总的来讲,有两大缺点:
if (err != null)
,真的很累,并且容易漏掉;run()
函数中的非异步的错误也没法处理;总的来讲,它并无比try/catch
好多少。
catch()
try/catch
和 Go 语言风格的异常处理都有各自的使用场景,可是处理全部异常最好的方法是在run()
函数的后面使用catch()
,像这样:run().catch()
。换句话说,用一个catch()
来处理run
函数中的全部错误,而不是针对run
里面的每一种状况都去写代码作相应的处理。
run()
.catch(function handleError(err) {
err.message; // Oops!
})
// 在handleError中处理全部的异常
// 若是handleError出错,则退出。
.catch(err => {
process.nextTick(() => {
throw err;
});
});
async function run() {
await Promise.reject(new Error("Oops!"));
}
复制代码
记住,async 函数老是返回 promise。只要函数中有异常,Promise 会 reject。并且,若是一个 async 函数返回的是一个 reject 的 Promise,那么这个 Promise 依然会继续被 reject。
run()
.catch(function handleError(err) {
err.message; // Oops!
})
.catch(err => {
process.nextTick(() => {
throw err;
});
});
async function run() {
// 注意:这里使用了return,而不是await
return Promise.reject(new Error("Oops!"));
}
复制代码
为何使用run().catch()
而不是将整个run()
函数用try/catch
包起来呢?咱们首先来考虑一个状况:若是try/catch
的catch
部分有异常,咱们应该如何处理呢?只有一个方法:在catch
里面接着使用try/catch
。因此,run().catch()
的模式使得异常处理变得很是简洁。
咱们最好是全局的有一个 errorHandler 来处理那些没有考虑到的异常,好比使用run().catch(handleError)
,而不是在run()
函数里面全部可能出错的地方加上try/catch
。
Fundebug专一于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对一、微脉、青团社等众多品牌企业。欢迎你们免费试用!
转载时请注明做者 Fundebug以及本文地址:blog.fundebug.com/2019/07/24/…