我是否应该避免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')));
这里prm3
和prm1
是一样的。
请参阅: 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); });