收藏本站

電腦請使用 Ctrl + D 加入最愛
手機請使用 收藏
關閉

小編的世界 優質文選 主機

服務器端JavaScript運行環境Node.js的依賴性管理


字體大小:
2021年5月27日 -
:     
 

51CTO

北京無憂創想信息技術有限公司

眾所周知,Node.js是一個基於Chrome V8引擎的服務器端JavaScript運行環境。它采用了一種事件驅動的、非阻塞式的I/O模式,運行起來既輕量級又高效。誠然,我們可以使用單個js文件,來編寫出應用程序所涉及到的全部內容,但這樣既不靈活,又不夠模塊化。而Node.js的出現,讓模塊化代碼的編寫變得非常簡便。因此,對於Node.js的核心,我們需要理解和掌握的一個重要概念便是:依賴關系的管理。本文將和您一起探討依賴項管理的各種模式,以及Nodejs是如何加載依賴項的。

在深入探討細節之前,讓我們首先弄清楚什麼是模塊。簡而言之,模塊是一段代碼。為了共享和重用,我們需要將代碼進行分組放置。通過模塊,我們可以將複雜的應用程序分解到小塊代碼中。同時,模塊也能夠幫助我們理解程序代碼的意圖,並發現或修複各種錯誤。

自2009年以來,CommonJS便實現了Javascript的模塊化規範。它規範了模塊的特性和各個模塊之間的相互依賴性。由於每個文件都被當做一個模塊(通常,module變量代表了當前模塊),而且有自己的作用域,因此每個文件裏面的變量、函數、以及類,都是私有的,且對於其他模塊是不可見的。而模塊的exports屬性便是對外的接口。只有通過exports導出的屬性,才能被其他模塊識別和加載。而Node是基於CommonJs規範來實現模塊的同步與加載。也就是說,我們可以通過在模塊中調用require()方法,來接收模塊的標識,並根據node的模塊引入規則,引入其他模塊,進而調用對應的屬性和方法。

在此,我假設您已經掌握了Nodejs的上述基礎知識。當然,如果您是一名Node.js的新手,則可以通過查看Node.js的相關簡介來了解更多背景信息。

設置應用

讓我們從最簡單的開始。假設我已經為某個項目創建了一個目錄。通過運用npm init命令對其初始化後,我們將創建app.js和appMsg.js,兩個JavaScript文件。下圖展示了本項目的目錄結構,我們將其作為管理的起點。如果您感興趣的話,可以從文末給出的git存儲庫鏈接中,下載該項目的最終源代碼。

默認情況下,這兩個.js文件均為空。讓我們通過如下更改,來更新appMsgs.js文件。

上面的代碼段展示了module.exports關鍵字的用法。此語法用於公開給定文件(此處為appMsgs.js)中的屬性或對象,以便能夠在另一個文件(如本例中的app.js)中被直接使用到。

在該系統中,每個文件都可以訪問到名為module.exports的文件。因此,我們在appMsgs.js文件中公開了一些項目,以方便觀察app.js是如何使用(require)某些屬性的。

顯然,require關鍵字可以方便我們引用某個文件。也就是說,當我們執行require時,它將返回一個代表著模塊化代碼段的對象。因此,我們可以將其分配給一個appMsgs變量,然後在console.log的語句中簡單地使用該屬性。當代碼被執行時,我們將看到如下輸出:

該require通過執行JavaScript,構造出一個具有某種功能函數的對象,作為返回。它們既可能是一個類構造函數,又可以是其中包含了許多元素、或一些簡單屬性的對象。針對不同的模式,我們既可以導出多個對象,又可以只導出那些複雜的對象。可見,通過require和module.exports,我們可以創建出模塊化的應用程序。

值得注意的是,應用程序所需的功能函數只會僅加載代碼一次。也就是說,無論執行了什麼代碼,它們都不會被執行第二次。那麼,如果別的程序也要通過require來獲取對象的話,它將只能獲得該對象的緩存版本。

下面,讓我們來看看導出的方式。

如上面代碼段所示,我對前面的代碼進行了更改。現在,我不再公布對象了,而是導出了一個功能函數(function)。該函數在每次被調用時,都需要執行該代碼。

下面,讓我們來看看如何在app.js文件中使用它:

更新app.js文件

除了調用某個屬性,我們還可以像執行函數一樣去執行它。因此,這裏的區別主要是,每當我們執行該代碼時,函數內部的代碼都會被重新執行(re-executed)。

下面是我們重新運行該代碼段的輸出:

至此,我們已經看到了module.exports的兩種模式,及其兩者的區別。還有一個常見的模式是,將其用作構造器方法(constructor method)。下面,讓我們再來看一個例子:

下面是更改過的app.js文件:

從本質上講,這與您在JavaScript中創建偽類(pseudo-class),並且創建它的各種實例(instances)是一致的。

下面是更改後的輸出:

接著,讓我們接著討論此類模式的另一個示例。如下代碼段所示,我創建了一個名為userRepo.js的新文件。

下面是更改後的app.js文件。

下圖是該更改被執行後的結果:

當然,針對單個文件都去使用require的情況並不常見。接下來,讓我們再討論另一種模式--文件夾的依賴性。

文件夾依賴性

為了弄清Node.js是如何查找依賴性的,讓我們重溫一下前面例子中的JavaScript代碼:

var appMsgs = require(“ ./appMsgs”)

Node不但會查找appMsgs.js文件,而且會查找作為目錄的appMsgs,並取出它的值。

我創建了一個名為logger的文件夾,並在其中創建了一個index.js文件,其內容如下面的代碼段所示:

下面是require此模塊的app.js文件:

可見,在本例中,我們可以寫出這樣的JavaScript代碼:

var logger = require(“./logger/index.js”)

上述較長的路徑形式肯定是正確的。但是,我們其實只需寫出如下的JavaScript代碼即可:

var logger = require(“./logger”)

由於沒有logger.js,而只有logger目錄,因此在默認情況下,Node將加載index.js作為logger的起點。我們可以通過如下命令,來驗證其輸出結果:

在此,您可能心生疑慮:我們為什麼如此費盡周折地創建文件夾和index.js呢?其背後的原因在於:您可能會將一些複雜的依賴項放在一起,而這些依賴項也可能還有其他的依賴項。而對於需要logger的調用者(caller)而言,它們不需要知道其他依賴項的存在。

這便是一種封裝形式(encapsulation)。我們完全可以在多個文件中,構建更為複雜的代碼段;而在使用者(consumer)角度,它們只需使用一個文件足矣。可見,文件夾是管理此類依賴性關系的更好方法。

Node程序包管理器(NPM)

第三類值得我們探討的依賴性管理是NPM。顧名思義,NPM是Node.js程序包的管理和分發工具,它相當於後端的Maven。它可以讓Javascript開發者更加輕松的共享和共用代碼段。

通常,我們可以使用如下npm命令,來安裝依賴項:

npm install underscore;

如下代碼段所示,我們也可以簡單地在app.js中require它:

如您所見,我們可以通過underscore的軟件包來使用各項功能。同理,當需要用到此類模塊時,我們並沒有指定文件的路徑,而只需使用其名稱即可。Node.js將會從您的應用程序的node_modules文件夾中,自動加載到其對應的模塊。

下面是代碼執行後的輸出結果:

小結

綜上所述,我們討論了Node.js是如何管理其依賴性關系的。您可以從Git存儲庫下載上述示例的源代碼。

  大家在看    
《MIR4(傳奇4)》免費開放 服務器登陸問題遭

《MIR4(傳奇4)》免費開放 服務器登陸問題遭

1U GPU Server 服務器 新一代 GP

1U GPU Server 服務器 新一代 GP

我國網絡受美國“根服務器”限制,一旦對方關閉,會

我國網絡受美國“根服務器”限制,一旦對方關閉,會

聯想 戴爾 華為 浪潮全系列 服務器 存儲 工作

聯想 戴爾 華為 浪潮全系列 服務器 存儲 工作

11.11什麼值得買?有顏又能打的PowerEd

11.11什麼值得買?有顏又能打的PowerEd

數據庫存儲服務器怎樣購買?看完以下五點再做決定

數據庫存儲服務器怎樣購買?看完以下五點再做決定

永劫無間服務器炸了,玩家大罵rnm退錢

永劫無間服務器炸了,玩家大罵rnm退錢

服務器崩潰!LOL手遊由於太過火爆,將禁止加速器

服務器崩潰!LOL手遊由於太過火爆,將禁止加速器

非常鑒定室|《你是我的榮耀》更新讓服務器崩了!這

非常鑒定室|《你是我的榮耀》更新讓服務器崩了!這

美國心虛啥?對服務器發動攻擊,企圖破壞調查德堡實

美國心虛啥?對服務器發動攻擊,企圖破壞調查德堡實