【问题标题】:Calling 'next()' from promises in a middleware causes 'next shouldn't be called more than once'从中间件中的 Promise 调用“next()”会导致“不应多次调用 next”
【发布时间】:2018-07-13 10:20:53
【问题描述】:

最近我将代码从 Express 更改为 Restify。老实说,我不确定以前是否曾经发生过,但我想确实发生过。

基本上在我的中间件中,我调用一个承诺方法,当它解析时,我调用next 并在下一个中间件中执行其他操作。当它被拒绝时,我还想拨打next,在某些情况下没有错误。否则它必须调用错误中间件,将err 传递给next

somePromise()
.then(()=>{
    next();
})
.catch((err)=>{
    if(err.someatt) next();
    else next(err)
});

它适用于somePromise 的预期结果。问题是nextthen-catch 链绑定。当下一个中间件出现错误时,它会调用catch 方法并再次调用next

我发现 next 有一个属性 called ,当我在再次调用 next 之前将其设置为 false 时,我摆脱了错误。但当然它是一种反模式。我在不同的中间件中也遇到了同样的问题,我也使用了 Promise(按预期调用 next,然后在 catch 语句中再次调用它)。

还有其他人遇到过这样的问题吗?

【问题讨论】:

  • 您可以尝试/捕获您对next() 的第一次调用,以便异常不会传播到您的.catch() 处理程序。或者,您可以使用 .then() 的两个参数,因此第一个 .then() 回调中的拒绝/异常不会转到该 catch 处理程序。
  • 是的!我已经做到了。问题是我需要调用错误中间件。我必须将它分成几部分,以便我可以从 try/catch 和中间件堆栈中调用它

标签: javascript node.js express promise restify


【解决方案1】:

把你的链条改成这样:

somePromise().then(() => {
  next();
}, err => {
  // error occurred in somePromise()
  if(err.someatt) next();
  else next(err);
}).catch(err => {
  // error occurred in .then()'s next()
  // don't call next() again
});

.then() 的可选第二个参数充当.catch() 回调,但仅在链中较高层抛出的错误时调用,而不是在相邻.then() 回调中抛出的错误时调用。

this awesome answer 借来的一个非常有用的流程图演示了.then(onFulfilled, onRejected).then(onFulfilled).catch(onRejected) 之间的区别:

【讨论】:

  • 感谢您的回答。但是如果我不能再次调用 next 我就不能真正使用我的错误中间件,对吧?!
  • @VictorFerreira 如果您的中间件抛出错误,那么您有一个需要修复的错误。要么你没有捕捉到一个离它发生的地方足够近的令人烦恼的/外生异常,要么你试图捕捉一个需要首先防止发生的愚蠢的异常。有关术语的解释,请参阅this article
  • 我当然明白。但奇怪的是,这个调用next 的中间件突然对应用程序中所有未捕获的错误负责。如果我不使用then-catch,它不会被这个中间件捕获。并且应用程序得到的错误是 'next cant be called more than once' 或 'uncaught promise denied' 。它不好,因为它是无声的或没有清楚地显示错误到底是什么
  • 然后使用我的模式,在链末尾的.catch() 回调中显示的任何错误都表明需要修复的错误。记录他们的stack 属性,它会准确显示错误的来源。
  • 是的!这是为什么.then(successHandler, errorHandler) 是模式,而不是通常所说的反模式的一个典型例子。
猜你喜欢
  • 1970-01-01
  • 2021-05-24
  • 2021-06-23
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多