Express中间件无法捕获异步/等待引发的错误,但是为什么呢? [英] Express middleware cannot trap errors thrown by async/await, but why?
问题描述
这两个中间件功能的行为有所不同,我无法弄清原因:
These two middleware functions behave differently and I cannot figure out why:
在这里,错误将被try/catch捕获:
Here, the error will get trapped by try/catch:
router.get('/force_async_error/0', async function (req, res, next) {
try{
await Promise.reject(new Error('my zoom 0'));
}
catch(err){
next(err);
}
});
但是在这里,错误将不会被try/catch捕获:
But here, the error will not get trapped by try/catch:
router.get('/force_async_error/1', async function (req, res, next) {
await Promise.reject(new Error('my zoom 1'));
});
我以为Express用try/catch封装了所有中间件功能,所以我看不出它的表现如何?
I thought Express wrapped all middleware functions with try/catch, so I don't see how it would behave differently?
我查看了Express源,处理程序如下:
I looked into the Express source, and the handler looks like:
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
if (fn.length > 3) {
// not a standard request handler
return next();
}
try {
fn(req, res, next); // shouldn't this trap the async/await error?
} catch (err) {
next(err);
}
};
那为什么为什么try/catch不能捕获抛出的错误?
so why doesn't the try/catch there capture the thrown error?
推荐答案
这是因为调用是异步的,请使用以下代码:
This is because the call is asynchronous, take this code :
try {
console.log('Before setTimeout')
setTimeout(() => {
throw new Error('Oups')
})
console.log('After setTimeout')
}
catch(err) {
console.log('Caught', err)
}
console.log("Point of non-return, I can't handle anything anymore")
如果运行它,您应该看到在Point of non-return
之后触发了错误.
当我们在throw
行时为时已晚,我们不在try
/catch
之外.此时,如果引发错误,则将无法捕获.
If you run it you should see that the error is triggered after Point of non-return
.
When we're at the throw
line it's too late, we're outside of try
/catch
. At this moment if an error is thrown it'll be uncaught.
您可以通过在呼叫者中使用async
/await
来解决此问题(与被呼叫者无关),即:
You can work around this by using async
/await
in the caller (doesn't matter for the callee), ie :
void async function () {
try {
console.log('Before setTimeout')
await new Promise((resolve, reject) =>
setTimeout(() => {
reject(new Error('Oups'))
})
)
console.log('After setTimeout')
}
catch(err) {
console.log('Caught', err.stack)
}
console.log("Point of non-return, I can't handle anything anymore")
}()
最后,这意味着Express要处理异步错误,您需要将代码更改为:
Finally, this means that for Express to handle async errors you would need to change the code to :
async function handle(req, res, next) {
// [...]
try {
await fn(req, res, next); // shouldn't this trap the async/await error?
} catch (err) {
next(err);
}
}
更好的解决方法:
像这样定义wrap
函数:
const wrap = fn => (...args) => Promise
.resolve(fn(...args))
.catch(args[2])
并像这样使用它:
app.get('/', wrap(async () => {
await Promise.reject('It crashes!')
}))
这篇关于Express中间件无法捕获异步/等待引发的错误,但是为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!