文 / Victor - AfterShipjavascript
譯 / 吳天成 - AfterShiphtml
如下面這種方式,寫單例很容易:java
let someModule
async getSomeModule() {
if (!someModule) {
someModule = await someAsyncOperationsToInitializeModule()
}
return someModule
}
module.exports = getSomeModule
複製代碼
一般以這種方式使用它:node
// in async function
const getSomeModule = require('./getSomeModule')
const someModule = await getSomeModule()
複製代碼
除非你但願將模塊的加載延遲到初次運行時,不然不鼓勵這種方式。api
由於,這將帶來不少不必的分支代碼(例如,if statement ),實際上咱們但願避免這種代碼。並且使用 let
語法將會中斷靜態代碼分析,致使 IDE 不能正確推導出 someModule
的類型。promise
請注意,node 的模塊系統默認爲單例(模塊在第一次required的時候將會被緩存[1])。因此一旦一個 promise
被 resolved
並導出,不管誰 require
(加載) 模塊,它將始終返回第一次 resolved
的結果。緩存
如下是隻使用const
來實現的方式:async
// NodeJs 方式的 async 單例
// someAsyncOperationsToInitializeModule 爲 async function
// 注意,此處執行函數,未 await
const someModule = someAsyncOperationsToInitializeModule()
module.exports = someModule
複製代碼
2 行代碼,就夠了。函數
你該如何使用這個模塊呢?ui
// in async function
// 不要用 "await getSomeModule()", 你不須要 `()`
const getSomeModule = require('./getSomeModule')
const someModule = await getSomeModule
複製代碼
someModule
的值絕對與【問題描述】中提到的代碼運行結果徹底相同。
你可能會注意到文件名最好更改成 ./someModule.js
或 ./asyncSomeModule.js
.
另一個可能會提出的問題是,咱們已經使用了 await getSomeModule()
,可是在當前方案中,被調整爲了 await getSomeModule
。若是咱們採用這種解決方案,將會對現有代碼形成很大的影響。
其實,只須要作一點點調整,就能夠保持以前的文件命名和調用方式。
// NodeJS 方式的 async 單例
const someModule = someAsyncOperationsToInitializeModule()
module.exports = () => someModule
複製代碼
如今,你無需改變任何外部代碼。這種實現 100% 向後兼容。也就是說,你無需改造模塊的調用方式,正如問題中所提到的調用方式同樣。
// in async function
const getSomeModule = require('./getSomeModule')
const someModule = await getSomeModule()
複製代碼