我是否应该避免asynchronous处理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假设asynchronous处理Promise拒绝可能是一件坏事。

但为什么呢?

“我应该不要asynchronous处理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:默认的未处理的拒绝检测行为中有一个激烈的讨论,关于asynchronous附加拒绝处理程序的承诺应该如何performance – 没有警告,没有警告,或者终止程序被禁止使用。 在未处理的拒绝规范项目的几个问题上进行了更多的讨论。

这个警告是为了帮助你find你忘记处理拒绝的情况,但有时你可能想避免这种情况。 例如,您可能想要创build一堆请求并将结果存储到一个数组中,以便稍后在程序的其他部分处理它。

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

避免警告

附加一个空的处理程序不会改变存储的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'))); 

这里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 。

我假设asynchronous处理Promise拒绝是一件坏事。

确实是这样。

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

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

 var prm = Promise.reject(new Error('fail')); prm.catch((err) => { setTimeout(() => { console.log(err.message); }, 0); });