本文来自:https://ekyu.moe/article/limits-of-native-promise-and-async-await/javascript
众所周知,Nodejs 已原生支持 Promise 和 async/await 关键字,异步控制已经变得更加方便。html
然而,现在仍有不少人选择使用第三方的 Promise 库(如 bluebird)和相似 async/await 的实现(如 co)。这并不彻底是历史缘由使然,而是原生 Promise 和 async/await 仍存在着许多不足之处。本文将简单地提出一些,但愿能抛砖引玉。java
尽管原生 Promise 提供了Promise.all
和Promise.race
这类基本的方法,但在平常使用中,咱们常常须要像Promise.map
、Promise.reduce
、Promise.promisify
、Promise.delay
、Promise#isPending
、Promise#cancel
、Promise#timeout
这样的方法。尽管要手动实现这些也不算难(除了Promise#cancel
),但一些第三方的 Promise 库已经实现了部分这类 feature,就暂且没有必要重复造轮子了。node
17-05-31 更新
刚刚发现 Nodejs 发布了 8.0.0,Changelog 中有一行吸引了个人注意。git
The new
util.promisify()
API has been added [99da8e8e02] #12442.es6
我查了一下文档,确实加了这个方法!好兴奋!!github
以前看到这个问题有提到原生 Promise 的效率问题,blubird 的做者 Petka Antonov 给出了回答,这里提一下回答中的要点。api
- V8 的 Promise 是用 JavaScript 而不是 C 实现的。即使使用 C 语言实现 Promise 也不能提升多少性能,由于实际上它所作的提挈都是在与 JavaScript 对象交互。
- V8 的 Promise 实现没有像 bluebird 同样的优化,好比它会为 Promise 的 handlers 建立数组,当每一个Promise都必需要建立一对数组的时候会消耗大量的内存,而实际上在 99.99% 的状况下都不会将一个 Promise 分支屡次,于是对这类状况进行优化能减少内存的使用。
- 即使 V8 的 Promise 像 bluebird 同样地被优化,它仍然会受到规范的牵制。这个 benchmark 用了
new Promise
(在 bluebird 中这被视为一种 anti-pattern),由于在 ES6 中并无别的办法来生成一个根 Promise。用new Promise
来建立一个 Promise 是极慢的。首先父函数会申请一个闭包,而后传入两个独立的闭包做为参数。算起来每生成一个 Promise 总共要申请三个闭包,然而相对于一个被优化的 Promise 而言,一个闭包都已是个更昂贵的对象了。
并非全部的环境都能随随便便地升级到能支持 Promise 和 async/await 的 node 版本,尤为是 async/await 须要 Nodejs 7.6.0 以上,在我写这篇 blog 的时候 Nodejs 的 LTS 版本仍是 6.10.3。而相比之下,不少第三方库都作了这个 polyfill。数组
目前没有办法向 async function 的调用返回值注入别的类型的 Promise,它返回的只能是原生的。而上文提到了原生 Promise 目前存在的不少不足,在不得不使用第三方 Promise 库的状况下,也不得不在不少地方放弃 async function。尽管,将一个原生的 Promise 转为 bluebird 的 Promise 倒也不是不可能,例如:promise
const Bluebird = require('bluebird'); const someTask = (async () => {})(); const bluebirdSomeTask = Bluebird.resolve(someTask); console.log(someTask instanceof Promise); //=> true console.log(bluebirdSomeTask instanceof Bluebird); //=> true
然而用 Bluebird.resolve
这种方法来进行转换看上去就很是 anti-pattern,也徒增了代码的复杂度。
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。
本文连接:https://ekyu.moe/article/limits-of-native-promise-and-async-await/