在Node.js中,使用Promise.prototype.finally

 

最近Promise.prototype.finally() 达到了TC39提案流程的第4阶段,这意味着其建议已被接受,并现已成为ECMAScript规范最新草案的一部分。由此看来,将其放入Node.js仅是时间问题。

本文将向您展示:如何使用Promise.prototype.finally()以及如何编写自己的简化polyfill

 

 

一、什么是Promise.prototype.finally()

 

假设您创建了一个新的promise:

 

您可以使用.then()函数将诺言链接在一起。

 

请注意,它.then()带有两个功能参数。第一个是onFulfilled(),如果兑现了promise,就会调用。第二个是onRejected(),如果拒绝了promise,则调用。

 

promise是可以处于以下三种状态之一的状态机

1.待定:基本操作正在进行中,但promise尚未实现或被拒绝

2.已完成:基础操作已成功完成,并且promise现在具有关联的价值

3.拒绝:基础操作由于某种原因而失败,并且promise现在具有关联的错误

 

此外,已兑现或已兑现的promise被称为“已结算”。

 

 

虽然.then()是承诺链的核心机制,但它并不是唯一的机制。promise也有一个.catch()功能是方便的错误处理。

 

该.catch()函数只是.then()使用onRejected处理程序而不使用onFulfilled处理程序的便捷速记:

 

就像.catch(),该.finally()功能是的便捷快捷方式.then()。区别在于,在兑现promise时即履行或拒绝promise时,.finally()执行功能onFinally。

.finally()在撰写本文时,该功能尚未包含在任何Node.js版本中,但promise.prototype.finally在npm上的模块具有polyfill。

 

上面的脚本将同时打印“已完成”和“已拒绝”,这是因为onFinally在实现promise时将调用处理程序,而不管promise是实现还是拒绝。然而,onFinally处理程序没有收到任何参数,所以你不能告诉的promise是否已兑现或拒绝。

 

该finally()函数返回一个承诺,让你可以更链.then(),.catch()和.finally()调用到返回值。finally()回报的promise将兑现与之挂钩的promise。例如,即使onFinally处理程序返回“ bar” ,下面的脚本仍将打印“ foo ”。

 

同样,即使该onFinally函数未触发任何错误,下面的脚本仍将打印“ foo” 。

 

上述脚本演示与工作的一个重要的细节finally():finally()不会为您处理promise rejections。finally()如何处理promise rejections值得更仔细的研究。

 

二、错误处理

 

该finally()功能并不意味着处理promise rejections。事实上,它会在函数执行后明确地抛出错误onFinally()。以下脚本将打印未处理的promise rejections警告。

 

像一样try/catch/finally,你通常想.finally()在一个链之后链接.catch()。

 

但是,该finally()函数返回一个Promise,因此没有什么可以阻止您在.catch()after之后链接.finally()。特别是,如果您的onFinally处理程序可能出错,例如,如果发出HTTP请求,则应.catch()在末尾添加a以处理可能发生的任何错误。

 

三、简化的Polyfill

 

我认为最简单的方法是编写自己的实现。该.finally()函数是一个不错的选择,因为官方的polyfill只有45行,并且大多数对于简单的概念证明不是必需的。

这是此简单的finally()polyfill可以解决的测试案例。下面的脚本应打印’foo’5次。

 

以下是简化的polyfill。

 

此实现背后的关键思想是onFinally处理程序可以返回promise。如果确实如此,则您需要.then()兑现该promise,并解决或拒绝最初的promise达成的目标。

您可以显式检查onFinally处理程序的返回值是否为Promise。但此时Promise.resolve()已经为您完成了此操作,并为您节省了几条if语句。

所以你只需确保跟踪初始promise所确定的值或错误,并确保返回的promise从finally()实现到初始已解决的值res,或重新抛出初始被拒绝的错误err。

 

四、继续

 

该Promise.prototype.finally()功能是撰写本文时8个第4阶段TC39提案之一,这意味着finally()Node.js还有7个其他新的核心语言功能。

 

该finally()功能是8个新功能中最令人兴奋的功能之一,因为它有望使异步操作后的清理工作更加整洁。例如,下面是我现在正在生产中运行的代码,在finally()函数执行完后,迫切需要释放锁。

 

对promise链感到困惑吗?异步/等待是在Node.js中撰写承诺的最佳方法。Await为您处理promise rejections,因此未处理的promise rejections就消失了。

 

我的新电子书Mastering Async / Await旨在使您对异步/等待的基础知识以及异步/等待如何在几小时内适应JavaScript生态系统有一个全面的了解。

 

原文:http://thecodebarbarian.com/using-promise-finally-in-node-js.html

翻译:新钛云服 魏建民