javascript - 为什么我会通过 await Promise.all 收到未处理的 Promise Rejection

标签 javascript node.js asynchronous promise

这是我的代码的一般结构:

(async () => {
  try {
    const asyncActions = []

    for (let i = 0; i < 3; i++) {
      await new Promise((resolve, reject) => setTimeout(resolve, 1000))

      for (let j = 0; j < 3; j++) {
        asyncActions.push(new Promise((resolve, reject) => setTimeout(reject, 1000)))
      }
    }

    await Promise.all(asyncActions)
    console.log('all resolved')
  }
  catch (e) {
    console.log('caught error', e)
  }
})()
我希望这能捕捉到 asyncActions 中发生的任何拒绝。因为它们应该由 Promise.all() 处理,但不知何故他们没有处理?控制台显示以下内容:
(node:9460) UnhandledPromiseRejectionWarning: undefined
(Use `node --trace-warnings ...` to show where the warning was created)
(node:9460) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9460) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:9460) UnhandledPromiseRejectionWarning: undefined
(node:9460) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
...

(node:9460) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
(node:9460) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 2)
...
为什么不被 Promise.all() 处理然后被捕获 block 捕获?
我还注意到,当我同时更换 new Promise(...)只需 Promise.resolve()Promise.reject()它分别捕获错误。这是为什么?两种变体不是异步的,因此应该以相同的方式工作吗?

最佳答案

我们在 Node.js 中检测未处理 promise 拒绝的方式是使用启发式。
当一个 Promise 被拒绝时,我们给用户一个仍然附加监听器(同步)的机会——如果他们不这样做,我们假设它没有被处理并导致 unhandledRejection .这是因为:

  • 不可能(如在停止问题中)知道用户将来是否会附加这样的处理程序。
  • 在绝大多数情况下,它就足够了,因为最好的做法是始终立即附加监听器。

  • 所以 - 您需要始终同步添加 catch 监听器,以避免未处理的拒绝。
    您也可以(在非人为的情况下)通过在 fork 中添加一个空的 catch 监听器来选择退出:
    (async () => {
      try {
        const asyncActions = []
    
        for (let i = 0; i < 3; i++) {
          await new Promise((resolve, reject) => setTimeout(resolve, 1000))
    
          for (let j = 0; j < 3; j++) {
            const p = new Promise((resolve, reject) => setTimeout(reject, 1000));
            p.catch(() => {}); // suppress unhandled rejection
            asyncActions.push(p)
          }
        }
    
        await Promise.all(asyncActions)
        console.log('all fulfilled')
      }
      catch (e) {
        console.log('caught error', e)
      }
    })()
    
  • 有趣的历史花絮 #1:我们考虑使用 GC 来检测 unhandledRejections - 人们发现它更令人困惑。
  • 有趣的历史花絮 #2:Chrome 做了同样的事情,但如果你添加一个监听器,实际上会追溯删除消息。
  • 有趣的历史花絮#3:这个启发式起源于 2013 年的 bluebird 。我 talk about it here .
  • 关于javascript - 为什么我会通过 await Promise.all 收到未处理的 Promise Rejection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67789309/

    相关文章:

    javascript - 弹出窗口内容不适用于 angularjs ng-click

    Javascript 提交页面上的所有表单

    javascript - Window.onload 与脚本延迟

    node.js - 根据 Node 的输入设置 Jade 模板中复选框的选中属性

    node.js - 在nodejs中异步创建文件夹

    c# - C# 中的异步属性

    javascript - 如何将 Rails current_user 传递给 AngularJS 工厂 API 调用?

    node.js - 页面加载时的主干获取集合

    javascript - 无服务器以合理的方式读取 POST 变量

    javascript - 链式命令总是按顺序执行吗?