本文來自: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/