欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Node.js模塊加載詳解

 更新時(shí)間:2014年08月16日 10:46:18   作者:Jack Yao  
這篇文章主要介紹了Node.js模塊加載詳解,本文講解了加載核心模塊、加載文件模塊、加載目錄模塊、從文件加載模塊等內(nèi)容,需要的朋友可以參考下

JavaScript是世界上使用頻率最高的編程語言之一,它是Web世界的通用語言,被所有瀏覽器所使用。JavaScript的誕生要追溯到Netscape那個(gè)時(shí)代,它的核心內(nèi)容被倉促的開發(fā)出來,用以對抗Microsoft,參與當(dāng)時(shí)白熱化的瀏覽器大戰(zhàn)。由于過早的發(fā)布,無可避免的造成了它的一些不太好的特性。

盡管它的開發(fā)時(shí)間很短,但是JavaScript依然具備了很多強(qiáng)大的特性,不過,每個(gè)腳本共享一個(gè)全局命名空間這個(gè)特性除外。

一旦Web頁面加載了JavaScript代碼,它就會被注入到全局命名空間,會和其他所有已加載的腳本公用同一個(gè)地址空間,這會導(dǎo)致很多安全問題,沖突,以及一些常見問題,讓bug即難以跟蹤又很難解決。

不過謝天謝地,Node為服務(wù)器端JavaScript定了一些規(guī)范,還實(shí)現(xiàn)了CommonJS的模塊標(biāo)準(zhǔn),在這個(gè)標(biāo)準(zhǔn)里,每個(gè)模塊有自己的上下文,和其他模塊相區(qū)分。這意味著,模塊不會污染全局作用域,因?yàn)楦揪蜎]有所謂的全局作用域,模塊之間也不會相互干擾。

本章,我們將了解幾種不同的模塊以及如何加載它們。

把代碼拆分成一系列定義良好的模塊可以幫你掌控你的應(yīng)用程序,下面我們將學(xué)習(xí)如何創(chuàng)建和使用你自己的模塊。

了解Node如何加載模塊

Node里,可以通過文件路徑來引用模塊,也可以通過模塊名引用,如果用名稱引用非核心模塊,Node最終會把模塊名影射到對應(yīng)的模塊文件路徑。而那些包含了核心函數(shù)的核心模塊,會在Node啟動時(shí)被預(yù)先加載。

非核心模塊包括使用NPM(Node Package Manager)安裝的第三方模塊,以及你或你的同事創(chuàng)建的本地模塊。

每個(gè)被當(dāng)前腳本導(dǎo)入的模塊都會向程序員暴露一組公開API,使用模塊前,需要用require函數(shù)來導(dǎo)入它,像這樣:

復(fù)制代碼 代碼如下:

var module = require(‘module_name')

上面的代碼會導(dǎo)入一個(gè)名為module_name的模塊,它可能是個(gè)核心模塊,也可以是用NPM安裝的模塊,require函數(shù)返回一個(gè)包含模塊所有公共API的對象。隨模塊的不同,返回的對象可能是任何JavaScript值,可以是一個(gè)函數(shù),也可以是個(gè)包含了一系列屬性(函數(shù),數(shù)組或者任何JavaScript對象)的對象。

導(dǎo)出模塊

CommonJS模塊系統(tǒng)是Node下文件間共享對象和函數(shù)的唯一方式。對于一個(gè)很復(fù)雜的程序,你應(yīng)該把一些類,對象或者函數(shù)重構(gòu)成一系列良好定義的可重用模塊。對于模塊使用者來說,模塊僅對外暴露出那些你指定的代碼。

在下面的例子里你將會了解到,在Node里文件和模塊是一一對應(yīng)的,我們創(chuàng)建了一個(gè)叫circle.js的文件,它僅對外導(dǎo)出了Circle構(gòu)造函數(shù)。

復(fù)制代碼 代碼如下:

function Circle(x, y, r) {

       function r_squared() {

              return Math.pow(r, 2);

       }

       function area() {

              return Math.PI * r_squared();

       }

       return {area: area};

}

module.exports = Circle;

代碼里最重要的是最后一行,它定義了模塊對外導(dǎo)出了什么內(nèi)容。module是個(gè)特殊的變量,它代表當(dāng)前模塊自身,而module.exports是模塊對外導(dǎo)出的對象,它可以是任何對象,在這個(gè)例子里,我們把Circle的構(gòu)造函數(shù)導(dǎo)出了,這樣模塊使用者就可以用這個(gè)模塊來創(chuàng)建Circle實(shí)例。

你也可以導(dǎo)出一些復(fù)雜的對象,module.exports被初始化成一個(gè)空對象,你把任何你想暴露給外界的內(nèi)容,作為module.exports對象的屬性來導(dǎo)出。比如,你設(shè)計(jì)了一個(gè)模塊,它對外暴露了一組函數(shù):

復(fù)制代碼 代碼如下:

                  function printA() {

         console.log('A');

}

function printB() {

         console.log('B');

}

function printC() {

         console.log('C');

}

module.exports.printA = printA;

module.exports.printB = printB;

module.exports.pi = Math.PI;

這個(gè)模塊導(dǎo)出了兩個(gè)函數(shù)(printA和printB)和一個(gè)數(shù)字(pi),調(diào)用代碼看起來像這樣:

復(fù)制代碼 代碼如下:

var myModule2 = require('./myModule2');

myModule2.printA(); // -> A

myModule2.printB(); // -> B

console.log(myModule2.pi); // -> 3.141592653589793

加載模塊

前面提到過,你可以使用require函數(shù)來加載模塊,不用擔(dān)心在代碼里調(diào)用require會影響全局命名空間,因?yàn)镹ode里就沒有全局命名空間這個(gè)概念。如果模塊存在且沒有任何語法或初始化錯(cuò)誤,require函數(shù)就會返回這個(gè)模塊對象,你還可以這個(gè)對象賦值給任何一個(gè)局部變量。

模塊有幾種不同的類型,大概可以分為核心模塊,本地模塊和通過NPM安裝的第三方模塊,根據(jù)模塊的類型,有幾種引用模塊的方式,下面我們就來了解下這些知識。

加載核心模塊

Node有一些被編譯到二進(jìn)制文件里的模塊,被稱為核心模塊,它們不能通過路徑來引用,只能用模塊名。核心模塊擁有最高的加載優(yōu)先級,即使已經(jīng)有了一個(gè)同名的第三方模塊,核心模塊也會被優(yōu)先加載。

比如,如果你想加載和使用http核心模塊,可以這樣做:

復(fù)制代碼 代碼如下:

         var http = require('http');

這將返回一個(gè)包含了http模塊對象,它包含了Node API文檔里定義的那些htpp模塊的API。

加載文件模塊

你也可以使用絕對路徑從文件系統(tǒng)里加載模塊:

復(fù)制代碼 代碼如下:

var myModule = require('/home/pedro/my_modules/my_module');

也可以用一個(gè)基于當(dāng)前文件的相對路徑:

復(fù)制代碼 代碼如下:

var myModule = require('../my_modules/my_module');

var myModule2 = require('./lib/my_module_2');

注意上面的代碼,你可以省略文件名的擴(kuò)展名,如果Node找不到這個(gè)文件,會嘗試在文件名后加上js后綴再次查找(譯者注:其實(shí)除了js,還會查找json和node,具體可以看官網(wǎng)文檔),因此,如果在當(dāng)前目錄下存在一個(gè)叫my_module.js的文件,會有下面兩種加載方式:

復(fù)制代碼 代碼如下:

var myModule = require('./my_module');

var myModule = require('./my_module.js');

加載目錄模塊

你還可以使用目錄的路徑來加載模塊:

復(fù)制代碼 代碼如下:

var myModule = require('./myModuleDir');

Node會假定這個(gè)目錄是個(gè)模塊包,并嘗試在這個(gè)目錄下搜索包定義文件package.json。

如果沒找到,Node會假設(shè)包的入口點(diǎn)是index.js文件(譯者注:除了index.js還會查找index.node,.node文件是Node的二進(jìn)制擴(kuò)展包,具體見官方文檔),以上面代碼為例,Node會嘗試查找./myModuleDir/index.js文件。

反之,如果找到了package.json文件,Node會嘗試解析它,并查找包定義里的main屬性,然后把main屬性的值當(dāng)作入口點(diǎn)的相對路徑。以本例來說,如果package.json定義如下:

復(fù)制代碼 代碼如下:

                   {

                            "name" : "myModule",

                            "main" : "./lib/myModule.js"

                   }

Node就會嘗試加載./myModuleDir/lib/myModule.js文件

從node_modules目錄加載

如果require函數(shù)的參數(shù)不是相對路徑,也不是核心模塊名,Node會在當(dāng)前目錄的node_modules子目錄下查找,比如下面的代碼,Node會嘗試查找文件./node_modules/myModule.js:

復(fù)制代碼 代碼如下:

var myModule = require('myModule.js');

如果沒找到,Node會繼續(xù)在上級目錄的node_modules文件夾下查找,如果還沒找到就繼續(xù)向上層目錄查找,直到找到對應(yīng)的模塊或者到達(dá)根目錄。

你可以使用這個(gè)特性來管理node_modules目錄的內(nèi)容或模塊,不過最好還是把模塊的管理任務(wù)交給NPM(見第一章),本地node_modules目錄是NPM安裝模塊的默認(rèn)位置,這個(gè)設(shè)計(jì)把Node和NPM關(guān)聯(lián)在了一起。通常,作為開發(fā)人員不必太關(guān)心這個(gè)特性,你可以簡單的使用NPM安裝,更新和刪除包,它會幫你維護(hù)node_modules目錄

緩存模塊

模塊在第一次成功加載后會被緩存起來,就是說,如果模塊名被解析到同一個(gè)文件路徑,那么每次調(diào)用require(‘myModule')都確切地會返回同一個(gè)模塊。

比如,有一個(gè)叫my_module.js的模塊,包含下面的內(nèi)容:

復(fù)制代碼 代碼如下:

console.log('module my_module initializing...');

module.exports = function() {

         console.log('Hi!');

};

console.log('my_module initialized.');

然后用下面的代碼加載這個(gè)模塊:

復(fù)制代碼 代碼如下:

var myModuleInstance1 = require('./my_module');

它會產(chǎn)生下面的輸出:

復(fù)制代碼 代碼如下:

module my_module initializing...

my_module initialized

如果我們兩次導(dǎo)入它:

復(fù)制代碼 代碼如下:

var myModuleInstance1 = require('./my_module');

var myModuleInstance2 = require('./my_module');

輸出依然是:

復(fù)制代碼 代碼如下:

module my_module initializing...

my_module initialized

也就是說,模塊的初始化代碼僅執(zhí)行了一次。當(dāng)你構(gòu)建自己的模塊時(shí),如果模塊的初始化代碼里含有可能產(chǎn)生副作用的代碼,一定要特別注意這個(gè)特性。

小結(jié)

Node取消了JavaScript的默認(rèn)全局作用域,轉(zhuǎn)而采用CommonJS模塊系統(tǒng),這樣你可以更好的組織你的代碼,也因此避免了很多安全問題和bug。可以使用require函數(shù)來加載核心模塊,第三方模塊,或從文件及目錄加載你自己的模塊

還可以用相對路徑或者絕對路徑來加載非核心模塊,如果把模塊放到了node_modules目錄下或者對于用NPM安裝的模塊,你還可以直接使用模塊名來加載。

 譯者注:

建議讀者把官方文檔的模塊章節(jié)閱讀一遍,個(gè)人感覺比作者講得更清晰明了,而且還附加了一個(gè)非常具有代表性的例子,對理解Node模塊加載會很有很大幫助。下面把那個(gè)例子也引用過來:

復(fù)制代碼 代碼如下:

用require(X) 加載路徑Y(jié)下的模塊

1. 如果X是核心模塊,

   a. 加載并返回核心模塊

   b. 結(jié)束

2. 如果X以 './' or '/' or '../ 開始'

   a. LOAD_AS_FILE(Y + X)

   b. LOAD_AS_DIRECTORY(Y + X)

3. LOAD_NODE_MODULES(X, dirname(Y))

4. 拋出異常:"not found"

LOAD_AS_FILE(X)

1. 如果X是個(gè)文件,把 X作為JavaScript 腳本加載,加載完畢后結(jié)束

2. 如果X.js是個(gè)文件,把X.js 作為JavaScript 腳本加載,加載完畢后結(jié)束

3. 如果X.node是個(gè)文件,把X.node 作為Node二進(jìn)制插件加載,加載完畢后結(jié)束

LOAD_AS_DIRECTORY(X)

1. 如果 X/package.json文件存在,

   a. 解析X/package.json, 并查找 "main"字段.

   b. 另M = X + (main字段的值)

   c. LOAD_AS_FILE(M)

2. 如果X/index.js文件存在,把 X/index.js作為JavaScript 腳本加載,加載完畢后結(jié)束

3. 如果X/index.node文件存在,把load X/index.node作為Node二進(jìn)制插件加載,加載完畢后結(jié)束

LOAD_NODE_MODULES(X, START)

1. 另DIRS=NODE_MODULES_PATHS(START)

2. 對DIRS下的每個(gè)目錄DIR做如下操作:

   a. LOAD_AS_FILE(DIR/X)

   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)

1. 另PARTS = path split(START)

2. 另ROOT = index of first instance of "node_modules" in PARTS, or 0

3. 另I = count of PARTS - 1

4. 另DIRS = []

5. while I > ROOT,

   a. 如果 PARTS[I] = "node_modules" 則繼續(xù)后續(xù)操作,否則下次循環(huán)

   c. DIR = path join(PARTS[0 .. I] + "node_modules")

   b. DIRS = DIRS + DIR

   c. 另I = I - 1

6. 返回DIRS

相關(guān)文章

  • nodejs的10個(gè)性能優(yōu)化技巧

    nodejs的10個(gè)性能優(yōu)化技巧

    在我接觸JavaScript(無論瀏覽器還是NodeJS)的時(shí)間里,總是遇到有朋友有多線程的需求。而在NodeJS方面,有朋友甚至直接說到,NodeJS是單線程的,無法很好的利用多核CPU。那么我們在使用過程中,就要非常注意性能優(yōu)化了
    2014-07-07
  • node.js+captchapng+jsonwebtoken實(shí)現(xiàn)登錄驗(yàn)證示例

    node.js+captchapng+jsonwebtoken實(shí)現(xiàn)登錄驗(yàn)證示例

    本篇文章主要介紹了node.js+captchapng+jsonwebtoken實(shí)現(xiàn)登錄驗(yàn)證示例,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • Node.js自動生成API文檔的實(shí)現(xiàn)

    Node.js自動生成API文檔的實(shí)現(xiàn)

    本文主要介紹了Node.js自動生成API文檔,包含基于swagger-jsdoc+swagger-ui-express快速實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Node.js Event Loop各階段講解

    Node.js Event Loop各階段講解

    今天小編就為大家分享一篇關(guān)于Node.js Event Loop各階段講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 解決Mac安裝thrift因bison報(bào)錯(cuò)的問題

    解決Mac安裝thrift因bison報(bào)錯(cuò)的問題

    今天小編就為大家分享一篇解決Mac安裝thrift因bison報(bào)錯(cuò)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • node.js使用zlib模塊進(jìn)行數(shù)據(jù)壓縮和解壓操作示例

    node.js使用zlib模塊進(jìn)行數(shù)據(jù)壓縮和解壓操作示例

    這篇文章主要介紹了node.js使用zlib模塊進(jìn)行數(shù)據(jù)壓縮和解壓操作,結(jié)合實(shí)例形式詳細(xì)分析了node.js基于zlib模塊創(chuàng)建數(shù)據(jù)流以及壓縮和解壓縮等相關(guān)操作技巧,需要的朋友可以參考下
    2020-02-02
  • Nestjs自定義注解實(shí)現(xiàn)接口權(quán)限控制詳解

    Nestjs自定義注解實(shí)現(xiàn)接口權(quán)限控制詳解

    這篇文章主要為大家介紹了Nestjs自定義注解實(shí)現(xiàn)接口權(quán)限控制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Node發(fā)出HTTP POST請求的方法實(shí)例小結(jié)

    Node發(fā)出HTTP POST請求的方法實(shí)例小結(jié)

    這篇文章主要介紹了Node發(fā)出HTTP POST請求的方法,結(jié)合實(shí)例形式總結(jié)分析了三種常用的post請求操作方法,以及相關(guān)庫操作注意事項(xiàng),需要的朋友可以參考下
    2023-05-05
  • 在nodeJs中如何修改json文件中的數(shù)據(jù)

    在nodeJs中如何修改json文件中的數(shù)據(jù)

    這篇文章主要介紹了在nodeJs中如何修改json文件中的數(shù)據(jù),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Nodejs環(huán)境Eggjs加簽驗(yàn)簽示例代碼

    Nodejs環(huán)境Eggjs加簽驗(yàn)簽示例代碼

    這篇文章主要介紹了Nodejs環(huán)境Eggjs加簽驗(yàn)簽示例代碼,文章開頭給大家介紹了加簽和驗(yàn)簽的基本概念,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07

最新評論