什么是未处理的承诺拒绝?


203

为了学习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中经历了不同的问题和答案,但找不到“未处理的承诺拒绝”是什么。

谁能简单地解释一下我的意思,它又是什么Error: spawn cmd ENOENT,什么时候出现,以及为了消除该警告我必须检查的内容?


2
我错过了这个问题!我很抱歉对此警告感到困惑-我们确实在较新的Node.js中对其进行了改进,并且很快将使整个过程变得更好!
本杰明·格伦鲍姆


@BenjaminGruenbaum,它已经解决了吗?我在节点v12.16.1上遇到了相同的错误
Baby desta

1
@Babydesta好吧,我们现在显示了一个更好的错误,带有堆栈跟踪,但是我们仍然不会在未处理的拒绝上使节点崩溃。为此,我们可能只需要打开PR。
Benjamin Gruenbaum

Answers:


200

此错误的根源在于,每个承诺都应处理承诺拒绝,即具有.catch(...)事实。您可以通过在以下代码中的Promise中添加.catch(...)来避免相同情况。

例如,函数PTest()将基于全局变量somevar的值解析或拒绝promise

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");
});

在某些情况下,即使我们为承诺编写了.catch(..),也会出现“未处理的承诺被拒绝”消息。这与您如何编写代码有关。即使我们正在处理,以下代码也会生成“未处理的承诺拒绝”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引擎将其视为未处理未处理的承诺被拒绝的承诺。


4
如果您添加myFunc = myFunct.then...第二个示例,这似乎可以工作。
einstein

@einstein,它似乎起作用,因为您正在重新创建与第一个示例相同的链:var x = foo(); x = x.then(...); x = x.catch(...)
randomsock

4
@einstein在你的奔放例如,当你说“出于某种原因,JavaScript引擎把它当作不承诺未办理承诺拒绝”,这不就是因为和异常可能会被抛出在.then(() => {...})处理?我不认为这与将它们链接在一起时做的事情相同。是吗?
西蒙·莱格

8
@DKG关于第二点,catch是的语法糖then(undefined, onRejected)。由于您已经在myfunc上调用了then并触发了错误,因此不会再次在相同的promise上调用then(undefined,onRejected)。
凯文·李

1
在哪里改变?当我按下ionic cordova build andorid命令给我这个错误时,我正在使用ionic 3。
萨加尔·科德

34

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

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

也可以看看


在哪里改变?当我按下ionic cordova build andorid命令给我这个错误时,我正在使用ionic 3。
萨加尔·科德

很难用这些信息来告诉。我建议您尝试创建最小的复制品,并针对您的具体情况创建一个新问题。
君特Zöchbauer

我为此悬赏。请查看一下stackoverflow.com/q/48145380/5383669
Sagar Kodte,

22

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

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

...在这种情况下,Promise被无声拒绝。如果忘记添加捕获处理程序,代码将继续以无提示的方式静默运行。这可能会导致挥之不去的错误。

对于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之前,ethnPromise被拒绝(错误:牙膏用完!)。在这种情况下,将有未处理的Promise拒绝,直到等待牙齿Promise。

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

有这个想法吗?

这与Node.js项目中的讨论相关:

默认的未处理拒绝检测行为

如果您以这种方式编写代码:

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 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);
}

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



2

在我的情况下,Promise不会拒绝也不会解决,因为Promise函数引发了异常。此错误导致UnhandledPromiseRejectionWarning消息。


1

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

在NodeJ中,不赞成使用拒绝处理程序。您的错误只是一个警告,我在node.js github中读取了它。我找到了这个。

DEP0018:未处理的承诺拒绝

类型:运行时

已弃用未处理的诺言拒绝。将来,未处理的承诺拒绝将以非零退出代码终止Node.js进程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.