在Node / Express中的异步函数中捕获错误

时间:2019-07-17 19:03:56

标签: node.js express asynchronous

从中间件或路由处理程序中调用Express next()res.send()后,是否有任何方法可以捕获异步回调中发生的错误?考虑以下代码:

app.use('/throw-error', (req, res) => {
  setTimeout(() => {
    throw new Error('Async error causes thread death')
  }, 500)

  res.send('This thread is going to die...')
})

它将执行并向浏览器发送“此线程将要死...”。半秒钟后,它也会使正在运行的Node线程崩溃。如果您碰巧正在运行一个使用Node的cluster模块的应用程序,则它可能会启动一个新线程,但仍然死亡。您可能会在日志中看到以下内容:

::1 [2019-07-17T18:54:55.142Z] - [71700] 4.740 ms "GET /throw-error" 200 -
/Users/moryl/Projects/crashtest/express.js:66
      throw new Error('Async error causes thread death')
      ^

Error: Async error causes thread death
    at Timeout.setTimeout [as _onTimeout] (/Users/moryl/Projects/InSight/sources/server/config/express.js:66:13)
    at ontimeout (timers.js:436:11)
    at tryOnTimeout (timers.js:300:5)
    at listOnTimeout (timers.js:263:5)
    at Timer.processTimers (timers.js:223:10)

该线程现在已死。

我的问题是,您是怎么处理正常请求范围之外的(可能未知的)异步错误的,无论是通过设计还是通过错误处理码?如何防止线程死亡?

我不想被告知我不应该在异步调用中做这种事情。我知道这个。我正在尝试编写防御性代码以捕获其他人编写的“坏东西”。

2 个答案:

答案 0 :(得分:3)

这已记录在express error handling doc中:

  

必须捕获路由调用的异步代码中发生的错误   处理程序或中间件,然后将其传递给Express进行处理。对于   例如:

app.get('/', function (req, res, next) {
  setTimeout(function () {
    try {
      throw new Error('BROKEN')
    } catch (err) {
      next(err)
    }
  }, 100)
})
     

上面的示例使用 try ... catch块来捕获错误,   异步代码并将其传递给Express。 如果try ... catch块   被省略了,Express不会捕获错误,因为它不是一部分   同步处理程序代码。

因此,基本上,您需要try..catch路线。 (示例基本相同,巧合)

答案 1 :(得分:1)

  

我的问题是,无论如何设计,您如何处理超出正常请求范围的异步错误...

您仍然希望处理异步代码中的错误,即使该错误已被触发并被设计遗忘。向每个独立任务添加try { } catch { }.catch。使用异步代码,Promises和async / await可以为您提供帮助(它们将独立的回调分组为任务,然后您可以处理每个任务的错误):

const timer = ms => new Promise(res => setTimeout(res, ms));

async function fireAndForgetThis() {
  await timer(500);
  throw new Error('Async error doesn't cause thread death, because its handled properly')
}

 fireAndForgetThis()
   .catch(console.error); // But always "handle" errors
  

...还是通过错误代码?

修正错误代码。

  

如何防止线程死亡?

这不是您要防止的事情。如果发生错误并且未进行处理,则您的应用程序将进入计划外状态。继续执行可能会产生更多问题。你不要那样您想防止未处理的拒绝/未处理的错误本身(通过正确处理)。


确定在某些情况下您无法处理,例如与备份数据库的连接断开。在这种情况下,NodeJS崩溃,导致监视唤醒DevOps,使数据库重新运行。崩溃也是处理错误;)

的一种形式

如果您已读到此,但仍想处理未处理的错误,请不要。好的,您可能有自己的理由,there you go