Express中间件无法捕获异步/等待引发的错误,但是为什么呢? [英] Express middleware cannot trap errors thrown by async/await, but why?

查看:196
本文介绍了Express中间件无法捕获异步/等待引发的错误,但是为什么呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这两个中间件功能的行为有所不同,我无法弄清原因:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆