什么是未处理的Promise拒绝?

IT技术 javascript angular es6-promise spawn unhandled-exception
2021-02-07 07:29:52

为了学习 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拒绝”是什么。

任何人都可以简单地向我解释它是什么以及它是什么Error: spawn cmd ENOENT,何时出现以及我必须检查什么才能摆脱此警告?

6个回答

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

例如,函数 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");
});

在某些情况下,即使我们为Promise编写了 .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");
});

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

嘿,你为我节省了几个小时的工作。现在我发现了前所未有的问题。
2021-03-15 07:29:52
@einstein 它似乎可以工作,因为您正在重新创建与第一个示例相同的链: var x = foo(); x = x.then(...); x = x.catch(...)
2021-03-16 07:29:52
@einstein在你的奔放例如,当你说“出于某种原因,JavaScript引擎把它当作不Promise未办理Promise拒绝”,这不就是因为和异常可能会被抛出在.then(() => {...})处理?我认为这与您将它们链接起来时做的事情不同。是吗?
2021-03-17 07:29:52
@DKG 关于你的第二点,catchthen(undefined, onRejected). 由于您已经在 myfunc 上调用 then 并且触发了错误,因此它不会再次在同一个 promise 上调用 then(undefined, onRejected) 。
2021-03-27 07:29:52
如果您添加myFunc = myFunct.then...第二个示例,它似乎有效
2021-04-02 07:29:52

这是当 aPromise完成.reject()或在async执行的代码中抛出异常并且 no .catch()did 处理拒绝时。

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

也可以看看

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

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

...在这种情况下,Promise 被默默拒绝。如果忘记添加 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;
}

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

我的观点是……如果我们认为未处理的 Promise 拒绝是一个问题,那么稍后由 await 处理的 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
}

当调用 getReadyForBed 时,它会同步创建最终的(未返回的)promise——它与任何其他 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);
}

请注意,这应该可以防止任何未处理的Promise拒绝。

“弃用警告:不推荐使用未处理的Promise拒绝”

TLDR:promise 有resolveand rejectreject不使用 catch 来处理它是不推荐使用的,所以你至少必须catch在顶层有一个 a

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