在顶层正确处理异步函数的异常

Properly handling exceptions from async functions at the top level

我无法理解在不触发 Node UnhandledPromiseRejectionWarning 的情况下处理异步函数异常的正确方法(因为这似乎表明我做错了什么)。

通常,在非异步代码中,未处理的异常会一直冒泡到顶部并最终打印到控制台。导致异常的代码一直停止返回堆栈。

假设我有以下代码:

test1().catch((e) => { throw e; });
console.log('got here top-level'); // This will print

async function test1() {
    let test2Result = await test2();
    console.log('got here test 1'); // This won't print
    return test2Result;
}

async function test2() {
    throw new Error('something failed here');
}

我希望这会做我想做的。在最顶层,它从异步函数中捕获异常并重新抛出(但现在在任何异步代码或 Promises 之外)。它应该仍然有原始的堆栈跟踪,这样我就可以找到问题所在。快乐的日子,对吧?但是不,这仍然导致 UnhandledPromiseRejectionWarning,我不明白为什么。

从 Promises 内部捕获所有未处理的异常的正确方法是什么?

你的误解来自于这个说法...

catches the exception from the async functions and re-throws (but now outside any async code or Promises)

Promise.prototype.catch() 仍然是异步代码。它 return 是一个 Promise,就像 .then() 一样(事实上,.catch(onRejected) 只是 .then(undefined, onRejected) 的别名)。

有趣的是,如果 .catch() 回调不是 return 被拒绝的承诺(例如 Promise.reject())或 throw,它 return 是成功的/ 已解决的承诺。

当你 throw e 在你的 .catch() 中时,return 值是一个被拒绝的 Promise,因为这是未处理/未捕获的,你会得到臭名昭著的 UnhandledPromiseRejectionWarning。 =22=]

为避免这种情况,只需处理所有可能的承诺拒绝

test1().catch(console.error); // returns a resolved promise

// or

try {
  await test1();
} catch (e) {
  // consider this handled
}

我通常会这样做:

async function main() {
  // do some async stuff here
  await someAsyncWork();
}

let cc;

main()
.then( () => {
  console.log('success!');
  cc = 0 ;
}
.catch( e => {
  console.error(e.stack);
  cc = 1;
})
.finally( () => process.exit(cc) );