成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

NodeJS中的模塊是單例的嗎?

開發(fā) 前端
筆者之前在使用require導(dǎo)入模塊時,特別是在導(dǎo)入有狀態(tài)的模塊時,筆者會考慮其是否在多次導(dǎo)入情況下依然保持單例特性,或者說對于同一個文件在不同路徑下導(dǎo)入時,是否能夠識別為一致?本文即是對該特性進(jìn)行解析。

本文翻譯自 Lazlojuly 的 are-node-js-modules-singletons。

本文從屬于筆者的NodeJS入門與***實(shí)踐中的NodeJS 基礎(chǔ)系列文章,包括NodeJS 入門、NodeJS 模塊導(dǎo)出與解析、NodeJS IOStream、NodeJS HTTPS這幾部分。

筆者之前在使用require導(dǎo)入模塊時,特別是在導(dǎo)入有狀態(tài)的模塊時,筆者會考慮其是否在多次導(dǎo)入情況下依然保持單例特性,或者說對于同一個文件在不同路徑下導(dǎo)入時,是否能夠識別為一致?本文即是對該特性進(jìn)行解析。

 NodeJS的模塊默認(rèn)情況下是單例性質(zhì)的,不過其并不能保證如我們編程時設(shè)想的那樣一定是單例,根據(jù)NodeJS的官方文檔中描述,某個模塊導(dǎo)入是否為單例受以下兩個因素的影響:

  • Node 模塊的緩存機(jī)制是大小寫敏感的,譬如如果你require('/foo')與require('/FOO')會返回兩個不同的對象,盡管你的foo與FOO是完全相同的文件。
  • 模塊是基于其被解析得到的文件名進(jìn)行緩存的,鑒于不同的模塊會依賴于其被調(diào)用的路徑進(jìn)行緩存鑒別,因此并不能保證你使用require('foo')會永遠(yuǎn)返回相同的對象,可能會根據(jù)不同的文件路徑得到不同的對象。

創(chuàng)建新的NodeJS模塊

根據(jù)NodeJS文檔所述,文件和模塊是一一對應(yīng)的關(guān)系。這個也是解釋上文提及的模塊緩存機(jī)制的基礎(chǔ),我們首先創(chuàng)建一個簡單的模塊:

  1. // counter.js  
  2.  
  3. let value = 0 
  4.  
  5. module.exports = { 
  6.   increment: () => value++, 
  7.   get: () => value, 

 在counter.js中我們創(chuàng)建了某個私有變量,并且只能通過公共的increment與get方法進(jìn)行操作。在應(yīng)用中我們可以如下方法使用該模塊: 

  1. // app.js 
  2. const counter = require(‘./counter.js’) 
  3.  
  4. counter.increment() 
  5. counter.increment() 
  6.  
  7. console.log(counter.get()) // prints 2 
  8. console.log(counter.value) // prints undefined as value is private  

Module Caching

NodeJS會在***次導(dǎo)入某個模塊之后將該模塊進(jìn)行緩存,在官方文檔中有如下描述:

Every call to require(‘foo’) will get exactly the same object returned, if it would resolve to the same file.

我們也可以通過如下簡單的例子來驗(yàn)證這句話: 

  1. // app-singleton.js 
  2.  
  3. const counter1 = require(‘./counter.js’) 
  4. const counter2 = require(‘./counter.js’) 
  5.  
  6. counter1.increment() 
  7. counter1.increment() 
  8. counter2.increment() 
  9.  
  10. console.log(counter1.get()) // prints 3 
  11. console.log(counter2.get()) // also prints 3  

可以看出盡管我們兩次導(dǎo)入了該模塊,但是還是指向了同一個對象。不過并不是每次我們導(dǎo)入同一個模塊時,都會得到相同的對象。在NodeJS中,模塊對象有個內(nèi)置的方法:Module._resolveFilename(),其負(fù)責(zé)尋找require中合適的模塊,在找到正確的文件之后,會根據(jù)其文件名作為緩存的鍵名。官方的搜索算法偽代碼為: 

  1. require(X) from module at path Y 
  2. 1. If X is a core module, 
  3.    a. return the core module 
  4.    b. STOP 
  5. 2. If X begins with './' or '/' or '../' 
  6. a. LOAD_AS_FILE(Y + X) 
  7.       1. If X is a file, load X as JavaScript text.  STOP 
  8.       2. If X.js is a file, load X.js as JavaScript text.  STOP 
  9.       3... 
  10.       4... 
  11. b. LOAD_AS_DIRECTORY(Y + X) 
  12.       1. If X/package.json is a file, 
  13.          a. Parse X/package.json, and look for "main" field. 
  14.          b. let M = X + (json main field) 
  15.          c. LOAD_AS_FILE(M) 
  16.       2. If X/index.js is a file, load X/index.js as JS text.  STOP 
  17.       3... 
  18.       4... 
  19. 3. LOAD_NODE_MODULES(X, dirname(Y)) 
  20. 4. THROW "not found"  

簡單來說,加載的邏輯或者說優(yōu)先級為:

  • 優(yōu)先判斷是不是核心模塊
  • 如果不是核心模塊則搜索node_modules
  • 否則在相對路徑中進(jìn)行搜索

解析之后的文件名可以根據(jù)module對象或得到: 

  1. // counter-debug.js 
  2.  
  3. console.log(module.filename) // prints absolute path to counter.js 
  4. console.log(__filename) // prints same as above 
  5. // i get: "/Users/laz/repos/medium/modules/counter-debug.js" 
  6.  
  7. let value = 0 
  8.  
  9. module.exports = { 
  10.   increment: () => value++, 
  11.   get: () => value,  

在上述的例子中我們可以看出,解析得到的文件名即使被加載模塊的絕對路徑。而根據(jù)文件與模塊一一映射的原則,我們可以得出下面兩個會破壞模塊導(dǎo)入單例性的特例。

Case Sensitivity

在大小寫敏感的文件系統(tǒng)中或者操作系統(tǒng)中,不同的解析之后的文件可能會指向相同的文件,但是其緩存鍵名會不一致,即不同的導(dǎo)入會生成不同的對象。 

  1. // app-no-singleton-1.js 
  2. const counter1 = require('./counter.js'
  3. const counter2 = require('./COUNTER.js'
  4.  
  5. counter1.increment() 
  6. console.log(counter1.get()) // prints 1 
  7. console.log(counter2.get()) // prints 0, not same object as counter1 
  8.  
  9. /*  
  10. We have two different resolved filenames: 
  11. - “Users/laz/repos/medium/modules/counter.js” 
  12. - “Users/laz/repos/medium/modules/COUNTER.js” 
  13. */  

在上面的例子中,我們分別用counter、COUNTER這僅僅是大小寫不同的方式導(dǎo)入相同的某個文件,如果是在某個大小寫敏感的系統(tǒng)中,譬如UBUNTU中會直接拋出異常:

 解析為不同的文件名

當(dāng)我們使用require(x)并且x不屬于核心模塊時,其會自動搜索node_modules文件夾。而在npm3之前,項(xiàng)目會以嵌套的方式安裝依賴。因此當(dāng)我們的項(xiàng)目依賴module-a與module-b,并且module-a與module-b也相互依賴時,其會生成如下文件路徑格式: 

  1. // npm2 installed dependencies in nested way 
  2. app.js 
  3. package.json 
  4. node_modules/ 
  5. |---module-a/index.js 
  6. |---module-b/index.js 
  7.     |---node_modules 
  8.         |---module-a/index.js  

這樣的話,我們對于同一個模塊就有兩個副本,那當(dāng)我們在應(yīng)用中導(dǎo)入module-a時,豈會載入如下文件: 

  1.  // app.js 
  2. const moduleA = require(‘module-a’) 
  3. loads: “/node_modules/module-a/index.js”  

而從module-b中載入module-a時,其載入的是如下文件: 

  1.  // /node_modules/module-b/index.js 
  2. const moduleA = require(‘module-a’) 
  3. loads “/node_modules/module-b/node_modules/module-a/index.js”  

不過在npm3之后,其以扁平化方式進(jìn)行文件加載,其文件目錄結(jié)構(gòu)如下所示: 

  1.  // npm3 flattens secondary dependencies by installing in same folder 
  2. app.js 
  3. package.json 
  4. node_modules/ 
  5. |---module-a/index.js 
  6. |---module-b/index.js  

不過此時就存在另一個場景,即我們應(yīng)用本身依賴module-a@v1.1與module-b,而module-b又依賴于module-a@v1.2,在這種情況下還是會采用類似于npm3之前的嵌套式目錄結(jié)構(gòu)。這樣的話對于module-a一樣會產(chǎn)生不同的對象,不過此時本身就是不同的文件了,因此相互之間不會產(chǎn)生沖突。

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2024-12-31 11:40:05

2023-12-05 08:20:05

單例模式Python

2013-03-26 10:35:47

Objective-C單例實(shí)現(xiàn)

2022-09-29 08:39:37

架構(gòu)

2015-10-27 09:19:24

2021-09-07 10:44:35

異步單例模式

2023-10-08 10:14:12

2011-06-28 15:18:45

Qt 單例模式

2024-12-03 16:49:58

2019-06-11 09:50:07

SparkBroadcast代碼

2022-02-06 22:30:36

前端設(shè)計模式

2023-11-13 16:49:51

C++單例

2020-01-09 12:30:20

架構(gòu)運(yùn)維技術(shù)

2021-04-29 07:18:21

Spring IOC容器單例

2021-03-15 07:02:02

java線程安全

2021-05-29 10:22:49

單例模式版本

2020-05-26 08:04:24

Shell腳本單例

2022-08-10 11:02:56

Python單例模式

2020-05-26 10:28:36

shell腳本單例運(yùn)行

2025-06-26 00:40:13

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美精品一区二区在线观看 | 一区二区三区国产好的精 | 日韩在线视频免费观看 | 97精品国产 | 国产小视频在线 | 日韩精品av一区二区三区 | 日本精品久久久久久久 | 欧美a在线看 | 中文字幕日韩一区 | 久久另类| 国产综合精品一区二区三区 | 天天艹日日干 | 九色视频网站 | 麻豆av片| 亚洲毛片 | 成人九色| 国产精品一区二区福利视频 | 亚洲国产成人精品女人 | 中文字幕日韩欧美一区二区三区 | 91亚洲国产精品 | 在线播放中文字幕 | 一级黄色片在线免费观看 | 国内精品视频在线观看 | 久久精品二区亚洲w码 | 香蕉av免费| 91成人精品| 国产一区二区三区在线免费 | 91在线网站| 国产精品婷婷 | 亚洲欧美一区二区三区在线 | 日韩在线播放av | 青草福利 | 国产久| 日韩高清中文字幕 | 亚洲欧美aⅴ | 国产成人精品久久 | 黄色毛片免费看 | 日韩免费在线视频 | 射久久 | 免费观看毛片 | 亚洲www啪成人一区二区 |