为什么延迟处理承诺拒绝有时会导致 UnhandledPromiseRejectionWarning?

Why does delaying handling of promise rejections sometimes result in UnhandledPromiseRejectionWarning?

当我运行以下代码时,为什么会收到未处理的承诺拒绝警告?

async function load() {
  throw new Error('error');
}

async function main() {
  const promise = load();

  await new Promise(resolve => setTimeout(resolve, 5000));

  try {
    await promise;
  } catch (e) {
    console.log('caught error', e);
  }
}

main();

这是输出:

jkim@dev-jkim test $ node index.js
(node:25276) UnhandledPromiseRejectionWarning: Error: error

由于 await promise 围绕着一个 try-catch,我很困惑为什么我的 try-catch 没有捕捉到错误。我想这与 setTimeout 有关,因为以下代码有效:

async function load() {
  throw new Error('error');
}

async function main() {
  const promise = load();
  try {
    await promise;
  } catch (e) {
    console.log('caught error', e);
  }
}

main();
jkim@dev-jkim test $ node index.js
caught error Error: error

这是怎么回事?如果在当前 tick 结束时未处理 promise 拒绝,是否会自动导致未处理的 promise 拒绝警告?

(我在节点 v10.16.3 上)

函数 load() 抛出 Error。如果在处理 Promise 时出现错误 thrown,则会拒绝 Promise。现在,如果抛出的错误 load() 没有被捕获,JS

会抛出 UnhandledPromiseRejectionWarning

您的代码的更好说明是:

function load() {
    console.log("hello after some time");
}

const foo = new Promise((resolve, reject) => {
    setTimeout(resolve, 5000);
})
.then(() => { load(); })
.catch((e) => { console.log(`Caught Error: ${e}`)});

If promise rejections are not handled by the end of the current tick, does it automatically result in a unhandled promise rejection warning?

是的。一个 Promise 必须 在它拒绝时附加一个拒绝处理程序,否则拒绝将被视为未处理。如果稍后附加拒绝处理程序,例如在

await new Promise(resolve => setTimeout(resolve, 5000));

当解释器到达

时,load Promise 已被拒绝
try {
  await promise;
} catch (e) {

所以,虽然拒绝可以被.catch捕捉到,但拒绝在拒绝的时候并没有被任何东西捕捉到,导致了警告。

此类事情的最佳做法是始终立即附加拒绝处理程序 - 无论这意味着 .catchtry/catch 还是 [=17] =],或者返回调用者处理的 Promise。