【问题标题】:What is an unhandled promise rejection?什么是未处理的承诺拒绝?
【发布时间】:2020-02-08 12:48:45
【问题描述】:

为了学习 Angular 2,我正在尝试他们的教程。

我收到这样的错误:

(node:4796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (r                                                                                                     ejection id: 1): Error: spawn cmd ENOENT
[1] (node:4796) 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.

我在 SO 中经历了不同的问题和答案,但找不到“未处理的 Promise Rejection”是什么。

谁能简单地解释一下它是什么以及Error: spawn cmd ENOENT 是什么,它何时出现以及我必须检查什么才能消除此警告?

【问题讨论】:

  • 我错过了这个问题!对于这个令人困惑的警告,我感到非常抱歉 - 我们确实在较新的 Node.js 中对其进行了改进,并且我们很快就会让整个事情变得更好!
  • @BenjaminGruenbaum,它修复了吗?我在节点 v12.16.1 上遇到了同样的错误
  • @Babydesta 好吧,我们现在通过堆栈跟踪显示了一个更好的错误,但我们仍然不会在未处理的拒绝时崩溃节点。我们可能只需要打开一个 PR 就可以做到这一点。

标签: javascript angular es6-promise spawn unhandled-exception


【解决方案1】:

当我有一个带有 Promised API 调用的 util 文件、一个调用它但没有显式处理 .catch 的组件以及一个模拟 Promise.reject 的 Jest 时,我看到了这一点: fetchStuff.mockImplementationOnce(() => Promise.reject(new Error('intentional fail')));

此外,这毒害了我的模拟,所以即使我在每次测试之前都调用了jest.resetAllMocks(),下一个测试会尝试渲染,并且渲染会调用 API,它会失败。之后的测试将恢复到良好的状态。我可以交换我的测试顺序,以证明它总是会毒害下一个渲染。

我尝试处理 API 中的错误,但没有成功。我尝试在我的 Jest 模拟中处理,但这也不起作用。我最终不得不做的是在我的组件中明确处理.catch。

【讨论】:

    【解决方案2】:

    在将数据发送到数据库之前不要关闭连接。从您的代码中删除client.close();,它会正常工作。

    【讨论】:

      【解决方案3】:

      我在 NodeJS 中遇到过类似的问题,罪魁祸首是 forEach 循环。请注意,forEach 是一个同步函数(非异步)。因此它只是忽略了返回的承诺。 解决方案是改用 for-of 循​​环: 我得到错误的代码:

      UnhandledPromiseRejectionWarning:未处理的承诺拒绝。此错误源于在没有 catch 块的情况下抛出异步函数内部,或拒绝未使用 .catch() 处理的承诺

      如下:

      permissionOrders.forEach( async(order) => {
              const requestPermissionOrder = new RequestPermissionOrderSchema({
                  item: order.item,
                  item_desc: order.item_desc,
                  quantity: order.quantity,
                  unit_price: order.unit_price,
                  total_cost: order.total_cost,
                  status: order.status,
                  priority: order.priority,
                  directOrder: order.directOrder
              });
      
              try {
                  const dat_order = await requestPermissionOrder.save();
                  res.json(dat_order);
              } catch(err){
                  res.json({ message : err});
              }
          });
      

      上述问题的解决方法如下:

      for (let order of permissionOrders){
              const requestPermissionOrder = new RequestPermissionOrderSchema({
                  item: order.item,
                  item_desc: order.item_desc,
                  quantity: order.quantity,
                  unit_price: order.unit_price,
                  total_cost: order.total_cost,
                  status: order.status,
                  priority: order.priority,
                  directOrder: order.directOrder
              });
      
              try {
                  const dat_order = await requestPermissionOrder.save();
                  res.json(dat_order);
              } catch(err){
                  res.json({ message : err});
              }
          };
      

      【讨论】:

        【解决方案4】:

        在我的情况下,Promise 没有拒绝也没有解决,因为我的 Promise 函数抛出了异常。这个错误会导致 UnhandledPromiseRejectionWarning 消息。

        【讨论】:

          【解决方案5】:

          这个错误的根源在于每个承诺都应该处理承诺拒绝,即有一个 .catch(...) 。您可以通过将 .catch(...) 添加到代码中的 Promise 中来避免这种情况,如下所示。

          例如,函数 PTest() 将根据全局变量 somevar

          的值解析或拒绝承诺
          var somevar = false;
          var PTest = function () {
              return new Promise(function (resolve, reject) {
                  if (somevar === true)
                      resolve();
                  else
                      reject();
              });
          }
          var myfunc = PTest();
          myfunc.then(function () {
               console.log("Promise Resolved");
          }).catch(function () {
               console.log("Promise Rejected");
          });
          

          在某些情况下,即使我们为 Promise 编写了 .catch(..),也会出现“未处理的 Promise 拒绝” 消息。这完全取决于您如何编写代码。即使我们正在处理catch,以下代码也会生成“未处理的承诺拒绝”。

          var somevar = false;
          var PTest = function () {
              return new Promise(function (resolve, reject) {
                  if (somevar === true)
                      resolve();
                  else
                      reject();
              });
          }
          var myfunc = PTest();
          myfunc.then(function () {
               console.log("Promise Resolved");
          });
          // See the Difference here
          myfunc.catch(function () {
               console.log("Promise Rejected");
          });
          

          不同之处在于您不将.catch(...) 视为链,而是作为单独的。由于某种原因,JavaScript 引擎将其视为没有未处理的 Promise 拒绝的 Promise。

          【讨论】:

          • 如果在第二个示例中添加myFunc = myFunct.then...,它似乎可以工作。
          • @einstein 它似乎可以工作,因为您正在重新创建与第一个示例相同的链:var x = foo(); x = x.then(...); x = x.catch(...)
          • @einstein 在您未链接的示例中,当您说“出于某种原因Java Script 引擎将其视为没有未处理的承诺拒绝的承诺”时,这不是因为@ 中可能会引发异常987654327@ 您没有处理?我认为这与您将它们链接在一起时所做的事情不同。是吗?
          • @DKG 关于第二点,catch 是then(undefined, onRejected) 的语法糖。由于您已经在 myfunc 上调用了 then 并且触发了错误,因此它不会再次在同一个 promise 上调用 then(undefined, onRejected) 。
          • 嘿,你为我节省了几个小时的工作时间。现在我发现了前所未有的问题。
          【解决方案6】:

          当我实例化一个 Promise 时,我将生成一个异步函数。如果函数运行良好,那么我调用 RESOLVE,然后流程在 RESOLVE 处理程序中继续,在 THEN.如果函数失败,则通过调用 REJECT 终止函数,然后在 CATCH 中继续流程。

          在 NodeJs 中,拒绝处理程序已被弃用。您的错误只是一个警告,我在 node.js github 中阅读了它。我找到了这个。

          DEP0018:未处理的承诺拒绝

          类型:运行时

          不推荐使用未处理的承诺拒绝。将来,未处理的 Promise 拒绝将使用非零退出代码终止 Node.js 进程。

          【讨论】:

            【解决方案7】:

            这是当 Promise 以 .reject() 完成时,或者在 async 执行的代码中引发异常并且没有 .catch() 处理拒绝。

            被拒绝的 Promise 就像一个向应用程序入口点冒泡并导致根错误处理程序产生该输出的异常。

            另见

            【讨论】:

              【解决方案8】:

              “DeprecationWarning:未处理的承诺拒绝已弃用”

              TLDR:promise 有 resolve 和 reject,不推荐使用 reject 而不使用 catch 来处理它,因此您必须至少在顶层有一个 catch。

              【讨论】:

                【解决方案9】:

                Promise 在被拒绝后可以“处理”。也就是说,可以在提供 catch 处理程序之前调用 Promise 的拒绝回调。这种行为对我来说有点麻烦,因为可以写...

                var promise = new Promise(function(resolve) {
                kjjdjf(); // this function does not exist });
                

                ... 在这种情况下,Promise 会被默默地拒绝。如果忘记添加 catch 处理程序,代码将继续静默运行而不会出错。这可能会导致难以发现的错误。

                在 Node.js 的情况下,有人谈到处理这些未处理的 Promise 拒绝并报告问题。这让我想到了 ES7 异步/等待。考虑这个例子:

                async function getReadyForBed() {
                  let teethPromise = brushTeeth();
                  let tempPromise = getRoomTemperature();
                
                  // Change clothes based on room temperature
                  let temp = await tempPromise;
                  // Assume `changeClothes` also returns a Promise
                  if(temp > 20) {
                    await changeClothes("warm");
                  } else {
                    await changeClothes("cold");
                  }
                
                  await teethPromise;
                }
                

                在上面的例子中,假设在 getRoomTemperature 完成之前,toothPromise 被拒绝了(错误:牙膏用完了!)。在这种情况下,将有一个未处理的 Promise 拒绝,直到 await toothPromise。

                我的意思是……如果我们认为未处理的 Promise 拒绝是一个问题,那么稍后由 await 处理的 Promise 可能会无意中被报告为错误。再说一次,如果我们认为未处理的 Promise 拒绝没有问题,则可能不会报告合法的错误。

                对此有什么想法?

                这与此处的 Node.js 项目中的讨论有关:

                Default Unhandled Rejection Detection Behavior

                如果你这样写代码:

                function getReadyForBed() {
                  let teethPromise = brushTeeth();
                  let tempPromise = getRoomTemperature();
                
                  // Change clothes based on room temperature
                  return Promise.resolve(tempPromise)
                    .then(temp => {
                      // Assume `changeClothes` also returns a Promise
                      if (temp > 20) {
                        return Promise.resolve(changeClothes("warm"));
                      } else {
                        return Promise.resolve(changeClothes("cold"));
                      }
                    })
                    .then(teethPromise)
                    .then(Promise.resolve()); // since the async function returns nothing, ensure it's a resolved promise for `undefined`, unless it's previously rejected
                }
                

                当 getReadyForBed 被调用时,它会同步创建最终的(未返回的)promise - 这将具有与任何其他promise 相同的“未处理拒绝”错误(当然,可能什么都没有,取决于引擎)。 (我觉得很奇怪你的函数没有返回任何东西,这意味着你的异步函数产生了一个未定义的承诺。

                如果我现在做出一个承诺而没有捕获,然后添加一个,大多数“未处理的拒绝错误”实现实际上会在我稍后处理它时收回警告。换句话说,async/await 不会以任何我能看到的方式改变“未处理的拒绝”讨论。

                为了避免这个陷阱,请这样写代码:

                async function getReadyForBed() {
                  let teethPromise = brushTeeth();
                  let tempPromise = getRoomTemperature();
                
                  // Change clothes based on room temperature
                  var clothesPromise = tempPromise.then(function(temp) {
                    // Assume `changeClothes` also returns a Promise
                    if(temp > 20) {
                      return changeClothes("warm");
                    } else {
                      return changeClothes("cold");
                    }
                  });
                  /* Note that clothesPromise resolves to the result of `changeClothes`
                     due to Promise "chaining" magic. */
                
                  // Combine promises and await them both
                  await Promise.all(teethPromise, clothesPromise);
                }
                

                请注意,这应该防止任何未处理的承诺拒绝。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-03-31
                  • 2023-03-17
                  • 2018-04-01
                  • 2021-09-19
                  • 1970-01-01
                  相关资源
                  最近更新 更多