一尘不染

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

javascript

我刚刚安装了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拒绝的 想法 /可能是一件坏事。

但是为什么呢?


阅读 686

收藏
2020-05-01

共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的位置与附加处理程序的位置分开。这些警告使执行起来更加困难,但是您可以处理事件(我的第一个示例),也可以在创建不想立即处理的承诺的任何地方附加虚拟捕获处理程序(第二个示例)。或者,您可以让一个模块为您完成(第三个示例)。

避免警告

如果分两个步骤执行,则附加空处理程序不会改变存储的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

2017更新

另请参见请求请求#6375:lib,src:对标记为Milestone8.0.0的未处理的承诺拒绝(自2017年2月起尚未合并)“抛出”:

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

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

2020-05-01