一尘不染

我应该避免异步处理Promise拒绝吗?

node.js

我刚刚安装了Node v7.2.0,并了解了以下代码:

var prm = Promise.reject(new Error('fail'));

结果消息:

(node:4786) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: fail
(node:4786) 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.

我理解这背后的原因,因为许多程序员可能经历了Error最终被吞噬的沮丧Promise。但是然后我做了这个实验:

var prm = Promise.reject(new Error('fail'));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
},
0)

结果是:

(node:4860) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: fail
(node:4860) 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.
(node:4860) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
fail

我基于 异步PromiseRejectionHandledWarning处理Promise拒绝的 想法 /可能是一件坏事。

但是为什么呢?


阅读 299

收藏
2020-07-07

共1个答案

一尘不染

“我应该避免异步处理Promise拒绝吗?”

这些警告起着重要的作用,但要查看其工作原理,请参见以下示例:

试试这个:

process.on('unhandledRejection', () => {});
process.on('rejectionHandled', () => {});

var prm = Promise.reject(new Error('fail'));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

或这个:

var prm = Promise.reject(new Error('fail'));
prm.catch(() => {});

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

或这个:

var var caught = require('caught');
var prm = caught(Promise.reject(new Error('fail')));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

免责声明:我是catch模块的作者(是的,我为这个答案写的)。

基本原理

它已作为v6和v7之间重大更改之一添加到Node中。在问题#830中进行了激烈的讨论:默认未处理的拒绝检测行为,没有关于异步连接拒绝处理程序的诺言应如何行为的通用协议-
无需警告即可工作,带有警告,或者通过终止程序而被禁止使用。在未处理拒绝规范项目的几个问题上进行了更多讨论。

此警告是为了帮助您找到忘记处理拒绝的情况,但有时您可能希望避免这种情况。例如,您可能要发出一堆请求并将结果的promise存储在数组中,以便稍后在程序的其他部分中进行处理。

相比于回调,promise的优点之一是您可以将创建Promise的位置与附加处理程序的位置分开。这些警告使操作变得更加困难,但是您可以处理事件(我的第一个示例),也可以在创建不想立即处理的承诺的任何地方附加虚拟捕获处理程序(第二个示例)。或者,您可以让一个模块为您完成(第三个示例)。

避免警告

如果分两个步骤执行,则附加空处理程序不会改变存储的promise的工作方式:

var prm1 = Promise.reject(new Error('fail'));
prm1.catch(() => {});

但是,这将是不同的:

var prm2 = Promise.reject(new Error('fail')).catch(() => {});

prm2将是一个不同的承诺prm1。虽然prm1将被拒绝并显示“失败”错误,但prm2将解决undefined您可能不想要的错误。

但是您可以编写一个简单的函数,使其像上面的两步示例一样工作,就像我对caught模块所做的那样:

var prm3 = caught(Promise.reject(new Error('fail')));

prm3与相同prm1

请参阅:https//www.npmjs.com/package/caught

2017更新

另请参阅请求标记#6375:lib,src:对未处理的诺言拒绝(自2017年2月起尚未合并)被标记为Milestone
8.0.0的

throw”

做出承诺“抛出”拒绝,这些拒绝 像常规的未捕获错误一样退出[重点添加]

这意味着我们可以期望Node 8.x将这个问题即将发生的 错误
的警告更改为崩溃并终止该过程,我们在今天编写程序时应考虑到这一点,以免将来出现意外情况。

另请参阅Node.js 8.0.0跟踪问题#10117

2020-07-07