如何以 Node.js 方式編寫單例

如何以 Node.js 方式編寫單例

文 / 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

解決方案 A

請注意,node 的模塊系統默認爲單例(模塊在第一次required的時候將會被緩存[1])。因此一旦一個 promiseresolved 並導出,不管誰 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。若是咱們採用這種解決方案,將會對現有代碼形成很大的影響。

其實,只須要作一點點調整,就能夠保持以前的文件命名和調用方式。

解決方案 B

// NodeJS 方式的 async 單例

const someModule = someAsyncOperationsToInitializeModule()

module.exports = () => someModule
複製代碼

如今,你無需改變任何外部代碼。這種實現 100% 向後兼容。也就是說,你無需改造模塊的調用方式,正如問題中所提到的調用方式同樣。

// in async function
const getSomeModule = require('./getSomeModule')
const someModule = await getSomeModule()
複製代碼

Show me the Code

repl.it/@victoratas…

補充資料

[1] nodejs.org/api/modules…

相關文章
相關標籤/搜索