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

为了学习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是什么,当它出现时,我必须检查什么来消除这个警告?

573715 次浏览

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

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

另请参阅

此错误的起源在于每个promise都被期望处理promise拒绝,即有< em > .catch(…)< / em >。你可以通过在下面给出的代码中的promise中添加< em > .catch(…)< / em >来避免同样的情况。

例如,函数PTest()将基于全局变量< em > < / somevar em >的值来解析或拒绝承诺

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引擎将其视为承诺,而没有未处理的承诺拒绝。

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

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

... 在这种情况下,承诺被默默地拒绝了。如果忘记添加catch处理程序,代码将继续无声地运行,没有错误。这可能会导致挥之不去且难以发现的bug。

在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之前,teethPromise被拒绝(错误:牙膏用完了!)。在这种情况下,将会有一个未处理的Promise拒绝,直到await teethPromise。

我的观点是…如果我们认为未处理的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被调用时,它将同步创建最终的(不返回的)承诺——它将具有与任何其他承诺相同的“未处理的拒绝”错误(当然,可能什么都没有,取决于引擎)。(我发现非常奇怪的是你的函数没有返回任何东西,这意味着你的async函数产生了一个未定义的承诺。

如果我现在做了一个没有catch的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);
}

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

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

TLDR: promise有resolvereject,执行reject而没有catch来处理它是不推荐的,所以你至少必须在顶层有一个catch

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

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

DEP0018:未处理的承诺拒绝

类型:运行时

不赞成未处理的承诺拒绝。将来,没有处理的promise拒绝将使用非零退出码终止Node.js进程。

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

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

UnhandledPromiseRejectionWarning:未处理的承诺拒绝。此错误是由于在没有catch块的异步函数中抛出,或者由于拒绝未使用.catch()处理的promise而引起的。

如下:

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

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

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

此外,这正在毒害我的模拟,因此即使我在每次测试之前调用jest.resetAllMocks(),下一个测试将尝试渲染,而该渲染将调用API,并且它将失败。测试后会回到良好的状态。我可以改变测试的顺序,以证明它总是会影响下一次渲染。

我尝试处理API中的错误,但没有成功。我试着在我的Jest mock中处理,但这也不起作用。我最终不得不在我的组件中显式地处理.catch