【问题标题】:Nodejs duplicate rejection (unhandled one and in a try/catch block) [duplicate]Nodejs重复拒绝(未处理的一个并在try / catch块中)[重复]
【发布时间】:2020-08-03 01:30:56
【问题描述】:

通过使用节点 js 12.16.1 LTS 我不明白为什么这段代码会导致双重拒绝(一个未处理,一个被捕获)。 当我删除 p 承诺并在 create_bug() 中等待 p 时,它运行良好(在 try catch 块中只捕获了一个拒绝)。我不知道为什么。

Nodejs 专家,您能帮忙吗?

'use strict';

process.on('uncaughtException', (err) => {
  console.error(`uncaughtException: ${JSON.stringify({name: err.name, msg: err.message})}`);
});
process.on('unhandledRejection', (err) => {
  console.error(`unhandledRejection: ${JSON.stringify({name: err.name, msg: err.message})}`);
});

async function create_bug() {
  console.log('In create');
  let res = superCreate();
  console.log(`In create, res = ${res}`);
  let p = new Promise((a, r) => setTimeout(() => a(), 0));
  await p;
  return res;
}


async function superCreate() {
  console.log('superCreate : now throwing');
  throw new Error("Something wrong");
}

async function create_OK() {
  console.log('In create');
  let res = await superCreate();
  console.log(`In create, res = ${res}`);
  let p = new Promise((a, r) => setTimeout(() => a(), 0));
  await p;
  return res;
}

async function main() {
  try {
    let res = await create_bug();
    console.log(`create result : ${res}`);
  } catch (err) {
    console.error(`ERROR caught in main : ${JSON.stringify({name: err.name, msg: err.message})}`);
  }
}

main().then(() => {
  setTimeout(() => console.log(`Finished`), 2000);
});

【问题讨论】:

  • 问题不在于你await p,问题在于你 await create_bug() 承诺——同时做一些异步的事情。
  • create_bug 在 main 中等待。我试图指出为什么当我从 create_bug (let p = ... and await p) 中删除两行时,我没有未处理的承诺。
  • 糟糕,我的意思是写superCreate()(返回被拒绝的承诺)而不是create_bug()

标签: node.js promise unhandled


【解决方案1】:

superCreate 变量 res 中包含的承诺未等待,并且在它被拒绝之前未附加 catch 处理程序.因此触发了未处理的承诺拒绝。当在main 中触发等待时,在拒绝后附加一个处理程序。

请注意,即使拒绝处理程序在被拒绝后附加到承诺上,也会调用拒绝处理程序。试试例如:

async function main() {
  let res = create_bug();
  try {
    await res;
    console.log(`create result : ${res}`);
  } catch (err) {
    console.error(`ERROR caught in main : ${JSON.stringify({name: err.name, msg: err.message})}`);
  }
  res.catch(err => console.error(`main1: ${JSON.stringify({name: err.name, msg: err.message})}`));
  res.catch(err => console.error(`main2: ${JSON.stringify({name: err.name, msg: err.message})}`));
}

请注意,您现在还会收到“main1”和“main2”错误。

或者,尝试从superCreate 函数中删除async,现在您应该看到In create, res = ${res} 没有打印,而是同步处理了异常。

另一种选择是直接从create_bug 返回res 而无需任何等待,而是在main 中等待res。然后您将看到与原始行为类似的行为:未处理的拒绝和“正常”捕获处理块。

async function create_bug() {
  console.log('In create');
  let res = superCreate();
  console.log(`In create, res = ${res}`);
  return res;
}

async function superCreate() {
  console.log('superCreate : now throwing');
  throw new Error("Something wrong");
}

async function main() {
  try {
    let res = create_bug();
    let p = new Promise((a, r) => setTimeout(() => a(), 0));
    await p;
    await res;
    console.log(`create result : ${res}`);
  } catch (err) {
    console.error(`ERROR caught in main : ${JSON.stringify({name: err.name, msg: err.message})}`);
  }
}

【讨论】:

  • 谢谢abondoa。我不知道要调用的拒绝处理程序,即使它在被拒绝后附加在承诺上。但是您如何解释当我从 create_bug 中删除 let p= ... 和 await p 行时,我没有未处理的拒绝?
  • 当您删除let p= ...await p 行时,您的res 会在它成为未处理的拒绝之前返回(然后在main 中等待),因为这一切都是同步发生的。尝试例如将let p= ...await p 行移动到您的主行中,因此它将调用create_bug(没有等待),然后创建并等待您的p,然后等待res。您将在此处看到类似的结果 - 即未处理的拒绝(因为 res 现在在等待/catch 附加之前在 main 中失败)和 catch 块中的“正常”错误处理。我也会更新答案。
  • 另外,请查看链接的问题/答案,它比我以往任何时候都更好地描述了这一点:stackoverflow.com/questions/46889290/…
猜你喜欢
  • 2019-02-28
  • 2020-08-20
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2015-10-03
  • 2019-04-15
相关资源
最近更新 更多