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

Moh*_*man 160 javascript unhandled-exception spawn es6-promise angular

为了学习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.
Run Code Online (Sandbox Code Playgroud)

我在SO中经历了不同的问题和答案,但无法找出"未处理的承诺拒绝"是什么.

任何人都可以简单地解释一下它是什么Error: spawn cmd ENOENT,也是什么,当它出现时,我必须检查以摆脱这个警告?

Dak*_*ksh 167

这个错误的根源在于每个承诺都应该处理承诺拒绝,即具有.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");
});
Run Code Online (Sandbox Code Playgroud)

在某些情况下,即使我们为promises编写了.catch(..),也会出现"未处理的promise 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");
});
Run Code Online (Sandbox Code Playgroud)

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

  • @DKG关于你的第二点,`catch`是`then(undefined,onRejected)`的语法糖.既然你已经在myfunc上调用了那个并且触发了一个错误,它就不会再次对同一个promise承诺(undefined,onRejected). (8认同)
  • @einstein在你的未链接的例子中,当你说"出于某种原因,Java脚本引擎将其视为没有未处理的承诺拒绝的承诺"时,这不是因为并且可以在`.then(()=> {中抛出异常...})`你**不是**处理?我不认为这与你链接时的做法是一样的.是吗? (4认同)
  • @einstein它看起来会起作用,因为您正在重新创建与第一个示例中相同的链:`var x = foo(); x = x.then(...); x = x.catch(...)` (3认同)
  • 它似乎工作,如果你在第二个例子中添加`myFunc = myFunct.then ...`. (2认同)
  • 嘿,你为我节省了几个小时的工作。现在我发现了前所未有的问题。 (2认同)

Gün*_*uer 31

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

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

也可以看看


ani*_*mer 20

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

var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });
Run Code Online (Sandbox Code Playgroud)

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

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

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;
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,假设在满足getRoomTemperature之前,teethPromise被拒绝(错误:没有牙膏!).在这种情况下,在等待teethPromise之前,将会有未处理的Promise拒绝.

我的观点是......如果我们认为未处理的Promise拒绝是一个问题,稍后由等待处理的Promise可能会无意中被报告为错误.然后,如果我们认为未处理的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
}
Run Code Online (Sandbox Code Playgroud)

当调用getReadyForBed时,它将同步创建最终(未返回)的promise - 它将具有与任何其他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);
}
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*ssy 11

"弃用警告:未处理的承诺拒绝被弃用"

TLDR:一个承诺已经过了,resolve并且rejectreject没有捕获的情况下处理它已被弃用,因此您必须至少拥有catch最高级别.