什么是未经处理的承诺拒绝
What is an unhandled promise rejection?
为了学习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
,什么时候出现,我必须检查什么才能摆脱这个警告?
这个错误的起源在于每个promise都被期望处理promise拒绝,即有一个.catch(…)。您可以通过在代码中的承诺中添加.catch(…)来避免相同的情况,如下所示。
例如,函数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");
});
在某些情况下,即使我们为承诺编写了.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引擎将其视为没有未处理的承诺拒绝的承诺。
这是当Promise
与.reject()
完成或在async
执行的代码中抛出异常并且没有.catch()
处理拒绝时。
被拒绝的承诺就像一个向应用程序入口点冒出来的异常,并导致根错误处理程序产生该输出。
参见
- https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
承诺在被拒绝后可以被"处理"。也就是说,可以在提供catch处理程序之前调用promise的reject回调。这种行为对我来说有点麻烦,因为一个人可以写…
var promise = new Promise(function(resolve) {
kjjdjf(); // this function does not exist });
…在这种情况下,承诺被无声地拒绝了。如果忘记添加catch处理程序,代码将继续静默运行,不会出现错误。这可能会导致难以发现的bug。
在Node.js的情况下,有讨论处理这些未处理的承诺拒绝并报告问题。这让我想到了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被拒绝了(Error: out of牙膏!)在这种情况下,会有一个未处理的Promise拒绝,直到await teethPromise。
我的观点是……如果我们认为未处理的Promise拒绝是一个问题,那么稍后由await处理的Promise可能会在无意中被报告为bug。然后,如果我们认为未处理的承诺拒绝没有问题,合法的错误可能不会被报告。对此有何感想?
这与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被调用时,它将同步创建最终(未返回)承诺-它将具有与任何其他承诺相同的"未处理拒绝"错误(当然,取决于引擎)。(我发现它很奇怪你的函数不返回任何东西,这意味着你的异步函数产生一个未定义的承诺。
如果我现在做一个没有catch的承诺,然后添加一个,大多数"未处理的拒绝错误"实现实际上会在我以后处理它时收回警告。换句话说,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:一个承诺有resolve
和reject
,做reject
而没有catch来处理它是不可取的,所以你必须至少有一个catch
在顶层。
在我的例子中是Promise,没有拒绝也没有解决,因为我的Promise函数抛出了一个异常。此错误导致UnhandledPromiseRejectionWarning消息
当我有一个带有承诺API调用的util文件时,我看到了这一点,一个调用它但没有显式处理.catch
的组件,以及一个模仿Promise.reject
的Jest:fetchStuff.mockImplementationOnce(() => Promise.reject(new Error('intentional fail')));
此外,这毒害了我的模拟,因此,即使我在每次测试之前调用jest.resetAllMocks()
,下一个测试将尝试渲染,渲染将调用API,它将失败。之后的测试将回到一个良好的状态。我可以交换我的测试顺序,以证明它总是会毒害下一次渲染。
我尝试处理API中的错误,但没有成功。我试着在我的笑话模拟处理,但没有工作,要么。我最终要做的是显式地处理组件中的.catch
。
我在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});
}
};
在向数据库发送数据之前尽量不要关闭连接。从代码中删除client.close();
,它将正常工作。
当我实例化promise时,我将生成一个异步函数。如果函数运行正常,那么我调用RESOLVE,然后流在RESOLVE处理程序中继续,在then中。如果函数失败,则通过调用REJECT终止函数,然后在CATCH中继续流。
在NodeJs中已弃用拒绝处理程序。你的错误只是一个警告,我在node.js github中阅读它。我发现了这个
DEP0018:未处理的承诺拒绝
类型:运行时
未处理的承诺拒绝已弃用。将来,未处理的承诺拒绝将以非零退出码终止Node.js进程。
- 我怎样才能让承诺拒绝测试
- Angularjs 承诺拒绝链接
- 承诺拒绝错误 - 未处理的拒绝错误:已关闭
- 连锁Angular承诺拒绝
- 知道操作是成功还是被承诺拒绝
- 异步承诺中未处理的承诺拒绝
- 可能的未处理承诺拒绝(id:0): undefined不是一个对象
- 什么是未经处理的承诺拒绝
- 未处理的承诺拒绝:不能调用方法'push'零
- Angular 2 - zone.js:355未处理承诺拒绝:模板解析错误:'不是已知元素:
- 使用CommonJS承诺:拒绝与异常
- 理解node.js中的承诺拒绝
- 为什么这是未处理的承诺拒绝
- 未处理的承诺拒绝:ReferenceError: _body没有定义
- 可能未处理的承诺拒绝- React-Native与Firebase
- 未处理的承诺拒绝:模板解析错误
- React Native错误:可能未处理的承诺拒绝-无法读取属性数据
- 未处理的承诺拒绝:推.On不是一个函数
- 回报的承诺.拒绝离子页
- 捕获所有未处理的javascript承诺拒绝