NodeJS 異步 API 允諾化
正文之前,我們先闡明幾個概念:
- 允諾(Promise):想必不需要解釋。這個概念貌似缺乏一個約定俗成的中文翻譯,這裏就現造一個罷。
- 允諾式(Promisive):基於允諾的異步編程方式,包括允諾鏈和異步函數等;一個對立面是回調式。
- 允諾化(Promisify):將非允諾式的程序或 API 轉化爲允諾式。
引子
允諾(Promise)是現代異步編程的基礎與核心,而 NodeJS 的設計早於允諾。 因此,其大量的異步 API 皆爲回調式。不進行允諾化(Promisify)改造,我們就無法方便地使用。 理想情況是官方修改這些 API 的行爲,當沒有回調函數傳入時,返回一個允諾。 然而這取決於官方的態度,由於這將破壞向後兼容,他們自然是要周全考慮,不可能輕易改動。 作爲普通用戶,我們只有自己動手了。
一個方案是將需要用的 API 進行再次封裝,鑑於異步 API 龐大的數量, 我們只能用到哪些封裝哪些。但這並不令人滿意。當我們用到新的 API 又得重新封裝; 並且,我們被迫要額外記憶封裝後的另一套 API;每個項目,每個開發者,又有不同的封裝方案。
最好是能用一個精簡的方式構造一個通用的解決方案。比如如下的方案:
定義
用法:
設計思路
分析 NodeJS 的異步 API 規範爲:不論接受幾個參數,最後一個參數爲回調函數, 並且回調函數所接受的第一個參數統一爲錯誤,第二個參數爲接口的響應。 據此設計通用的 Do 函數。
Do 函數的用法略顯彆扭。如果我們只使用某個模塊中的異步函數,就可將整個模塊允諾化,
提供更順手的 API。可以使用一個原模塊的代理(Proxy)對象,攔截接口的訪問,
並返回封裝層,通過 Do 函數訪問接口。這裏對封裝層作了緩存,目的是使每一次訪問都獲取到同一個函數,
避免出現 pfs.readFile !== pfs.readFile
的詭異現象。