Promise.catch是吞咽错误

Promise.catch is swallowing errors

本文关键字:错误 catch Promise      更新时间:2023-09-26

我在 Node 中做了很多异步编码.js回调和出色的异步库,效果很好。我正在尝试使用使用承诺的模块,但我遇到了一个问题,即在承诺之后抛出的任何错误仍然冒泡并被承诺错误处理程序捕获。

这使得调试错误变得非常困难,因为我不知道它们会在哪里弹出,它们不能被抛出也不会使应用程序崩溃。

下面的示例代码;我想做的只是退出承诺链,并在解决后将其抛在脑后,而不是捕获与它无关的所有后续错误。

function one (input, callback) {
  doSomeAsyncWork(input)
  .then(function (result) {
    return callback(null, result);
  })
  .catch(function (err) {
    logError(err);
    return callback(err);
  });
}
function two (err, result) {
  if (err) { ... }
  var x = callAMethodThatThrows();
  ...
}
one('abc', two);

在这个例子中,方法callAMethodThatThrows()抛出一个错误,该错误被冒泡到promise catch()块。这可以防止应用程序崩溃并使其处于未知状态。

任何建议将不胜感激,谢谢。

是的,很抱歉 - 我们正在修复(1)Node中的默认行为。与此同时,我指定并添加 Petka (在其他人的支持下)一个钩子来查找这些错误:

process.on("unhandledRejection", (err, p) => {
    console.error(err); // print the error
});

请注意,如果您本身异步执行.catch,这可能会捕获一些漏报 - 根据我的经验,这种情况非常罕见。

另请注意,有了承诺,您的服务器通常不会处于未知状态,您可以并且应该在有意义时尝试从错误中恢复。由于承诺一直意味着抛出安全代码,因此您可以进行细粒度的错误处理。

请注意,承诺使得异步库在很大程度上是不需要的。如果你仍然希望使用回调,只是希望"那些讨厌的承诺"会让你一个人呆着,让你继续写回调,那很好 - 承诺是安全的,但你可以通过执行承诺代码逃避它:

myPromiseFn().then(v => {
    process.nextTick(() => cb(null, v)); // next tick, to escape the chain
}, e => process.nextTick(() => cb(e));

请注意,公平承诺库还附带了一个asCallback回调,用于将承诺代码转换为节点错误回调。

(1)有人说没问题,去图吧

多亏了Ben的回答,我发现可以使用nodeify等模块将承诺转换为回调。这使我们能够使用回调来保留所有代码,并避免错误被承诺吞噬。非常有用。