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

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

但为什么呢?


“我是否应该避免异步处理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);

免责声明:我是被捕获模块的作者(是的,我为这个答案写了它)。

合理

它作为v6和v7之间的重大更改之一添加到节点。 在问题#830:默认未处理拒绝检测行为方面有一个激烈的讨论,并没有普遍认同异步附加拒绝处理程序的承诺应该如何行为 - 没有警告,工作警告或被终止程序禁止使用。 在未处理的拒绝规范项目的几个问题上进行了更多的讨论。

此警告旨在帮助您找到您忘记处理拒绝的情况,但有时您可能想避免这种情况。 例如,您可能想要制作一堆请求并将所得到的承诺存储在一个数组中,以便稍后在程序的其他部分处理它。

与回调有关的承诺的优点之一是,您可以将创建承诺的地点与附加处理程序的位置(或地点)分开。 这些警告让事情变得更加困难,但是您可以处理事件(我的第一个示例),或者在创建您不想立即处理的承诺的地方附加一个虚拟捕获处理程序(第二个示例)。 或者你可以有一个模块为你做(第三个例子)。

避免警告

附加空处理程序不会以任何方式改变存储承诺的工作方式,如果分两步执行:

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

这里prm3prm1相同。

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

2017更新

另请参见合并请求#6375:lib,src:在未处理的承诺拒绝(未于2017年2月合并)中标记为Milestone 8.0.0的“抛出”:

使承诺“抛出” 退出,就像常规未被捕获的错误一样退出 。 [着重点]

这意味着我们可以期望Node 8.x将这个问题所发出的警告转变为一个错误 ,这个错误会导致崩溃并终止这个过程,我们应该在编写我们的程序时考虑到它,以避免将来出现意外。

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


我认为异步处理Promise拒绝是一件坏事。

确实如此。

预计你想立即处理任何拒绝。 如果你没有做到(可能无法处理它),你会得到一个警告。
我几乎没有遇到任何你不想在遭到拒绝后立即失败的情况。 即使你在失败后需要等待更多的东西,你也应该明确地做到这一点。

我从来没有见过这样的情况,即不可能立即安装错误处理程序(试图说服我,否则)。 在你的情况下,如果你想要一个稍微延迟的错误信息,就这样做

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

prm.catch((err) => {
    setTimeout(() => {
        console.log(err.message);
    }, 0);
});
链接地址: http://www.djcxy.com/p/55345.html

上一篇: Should I refrain from handling Promise rejection asynchronously?

下一篇: cancel chained calls, trigger error chain