前言
为了能够更好地处理异步流程,一般开发者会选择 async 语法。在 express 框架中可以直接利用 async 来声明中间件方法,但是对于该中间件的错误,无法通过错误捕获中间件来劫持到。
错误处理中间件
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
const message = doSomething();
res.send(message);
});
// 错误处理中间件
app.use(function (err, req, res, next) {
return res.status(500).send('内部错误!');
});
app.listen(PORT, () => console.log(`app listening on port ${PORT}`));
以上述代码为例,中间件方法并没有通过 async 语法来声明,如果 doSomething 方法内部抛出异常,那么就可以在错误处理中间件中捕获到错误,从而进行相应地异常处理。
app.get('/', async (req, res) => {
const message = doSomething();
res.send(message);
});
而采用 async 语法来声明中间件时,一旦 doSomething 内部抛出异常,则错误处理中间件无法捕获到。
❝虽然可以利用 process 监听 unhandledRejection 事件来捕获,但是无法正确地处理后续流程。
❞
try/catch
对于 async 声明的函数,可以通过 try/catch 来捕获其内部的错误,再使用 next 函数将错误递交给错误处理中间件,即可处理该场景:
app.get('/', async (req, res, next) => {
try {
const message = doSomething();
res.send(message);
} catch(err) {
next(err);
}
});
「这种写法简单易懂,但是满屏的 try/catch 语法,会显得非常繁琐且不优雅。」
高阶函数
对于基础扎实的开发来说,都知道 async 函数最终返回一个 Promise 对象,而对于 Promsie 对象应该利用其提供的 catch 方法来捕获异常。
那么在将 async 语法声明的中间件方法传入 use 之前,需要包裹一层 Promise 函数的异常处理逻辑,这时就需要利用高阶函数来完成这样的操作。