Node.js中的模塊機制學(xué)習(xí)筆記
Javascript自誕生以來,曾經(jīng)沒有人拿它當(dāng)做一門編程語言。在Web 1.0時代,這種腳本語言主要被用來做表單驗證和網(wǎng)頁特效。直到Web 2.0時代,前端工程師利用它大大提升了網(wǎng)頁上的用戶體驗,JS才被廣泛重視起來。在JS逐漸流行的過程中,它大致經(jīng)歷了工具類庫、組件庫、前端框架、前端應(yīng)用的變遷。Javascript先天就缺乏一項功能:模塊,而CommonJS規(guī)范的出現(xiàn)則彌補了這一缺陷。本文將介紹CommonJS規(guī)范及Node的模塊機制。
在其他高級語言中,Java有類文件,Python有import機制,PHP有include和require。而JS通過<script>標(biāo)簽引入代碼的方式顯得雜亂無章。過去人們不得不用命名空間等方式來人為地約束代碼,直到CommonJS規(guī)范的出現(xiàn),前后端的Javascript才得以實現(xiàn)大一統(tǒng)。Node借鑒了CommonJS的Modules規(guī)范實現(xiàn)了一套非常易用的模塊系統(tǒng)。
1. CommonJS模塊規(guī)范
CommonJS的模塊規(guī)范分為3個部分:
1).模塊引用:通過require()方法并傳入一個模塊標(biāo)識來引入一個模塊的API到當(dāng)前上下文中,如var math = require('math');
2).模塊定義:通過exports對象來導(dǎo)出當(dāng)前模塊的方法或變量。模塊中還存在一個module對象,exports實際上是module的屬性。在Node中,一個文件就是一個模塊,模塊內(nèi)的“全局變量”對外都不可見,只有掛載在exports上的屬性才是公開的,如exports.add = function() {}; exports.PI = 3.1415926;
3).模塊標(biāo)識:實際上就是傳遞給require()的參數(shù),如上述的'math',它必須是符合camel命名法的字符串,或者是以“.”“..”開頭的相對路徑或絕對路徑,它可以沒有文件名后綴“.js”
2. Node模塊實現(xiàn)過程
在Node中,模塊分為兩類:一類是Node本身提供的核心模塊,另一類是用戶自己編寫的文件模塊。核心模塊有一部分在Node源代碼的編譯過程中,編譯成了二進(jìn)制文件,在Node啟動時核心模塊就被直接加載進(jìn)內(nèi)存中,所以它的加載速度是最快的。文件模塊則是在運行時動態(tài)加載,需要經(jīng)歷三個步驟:路徑分析,文件定位,編譯執(zhí)行。注意,Node對引入過的模塊都會進(jìn)行緩存,以減少二次引入時的開銷,并對相同模塊的二次加載都采用最優(yōu)先從緩存加載的策略。
2.1 路徑分析
路徑分析主要分析上述提到的模塊標(biāo)識符,主要分為以下幾類:
1)、核心模塊,如http、fs、path等
2)、.或..開始的相對路徑文件模塊
3)、以/開始的絕對路徑文件模塊
4)、自定義文件模塊,可能是一個文件或包的形式。Node會根據(jù)模塊路徑數(shù)組module.paths來逐個嘗試查找目標(biāo)文件,通常是沿著當(dāng)前目錄逐級向上直到根目錄查找名為node_modules的目錄,所以這是查找最費時的一種方式。
2.2 文件定位
在路徑分析的基礎(chǔ)上,文件定位需要注意如下細(xì)節(jié):
1)、文件擴展名分析:由于CommonJS規(guī)范允許模塊標(biāo)識不填寫擴展名,Node會按.js、.json、.node的次序不足擴展名,依次嘗試
2)、目錄分析和包:若通過上述文件擴展名分析后沒有查找到對應(yīng)文件,卻得到一個目錄,Node會把目錄當(dāng)做一個包來處理
2.3 編譯執(zhí)行
定位到具體文件后,Node會新建一個模塊對象,根據(jù)路徑載入并編譯。對于不同的擴展名,載入方法有所不同:
1)、.js文件:通過fs模塊同步讀取文件并編譯執(zhí)行
2)、.node文件:這是用C/C++編寫的擴展文件,通過dlopen()方法加載
3)、.json文件:通過fs模塊同步讀取文件,用JSON.parse()解析返回結(jié)果
4)、其余擴展名文件:都被當(dāng)做.js文件載入
我們知道每個模塊文件中默認(rèn)都存在著require、exports、module這3個變量,甚至在Node的API文檔中,我們知道每個模塊還有filename、dirname這2個變量的存在,它們是從何而來的呢?Node的模塊又是怎么做到聲明的“全局變量”實際上是不會污染到其他模塊的?事實上,Node在編譯JS模塊過程中會對文件內(nèi)容進(jìn)行頭尾包裝。下面是一個JS文件經(jīng)過頭尾包裝的例子:
(function(exports, require, module, __filename, __dirname) {
/* 中間是JS文件的實際內(nèi)容 */
var math = require('math');
exports.area = function(radius) {
return Math.PI * radius * radius;
};
/* JS文件的實際內(nèi)容結(jié)束 */
});
這樣每個模塊文件之間都進(jìn)行了作用域隔離,同時require、exports、module等變量也被注入到了模塊的上下文當(dāng)中。這就是Node對CommonJS模塊規(guī)范的實現(xiàn)。關(guān)于C/C++模塊及Node核心模塊的編譯過程較為復(fù)雜,不再贅述。
3. 模塊調(diào)用棧
有必要明確一下Node中各種模塊的調(diào)用關(guān)系,如下圖所示:
C/C++內(nèi)建模塊是最底層的模塊,屬于核心模塊,主要提供API給Javascript核心模塊和第三方Javascript文件模塊調(diào)用,實際中幾乎不會接觸到此類模塊。Javascript核心模塊主要職責(zé)有兩種:一種是作為C/C++內(nèi)建模塊的封裝層和橋接層供文件模塊調(diào)用,另一種是純粹的功能模塊,不需要跟底層打交道。文件模塊通常由第三方編寫,包括普通Javascript模塊和C/C++擴展模塊。
4. 包與NPM
4.1 包結(jié)構(gòu)
包本質(zhì)上是一個存檔文件(一般為.zip或.tar.gz),安裝后解壓還原為目錄。CommonJS的包規(guī)范由包結(jié)構(gòu)和包描述文件兩部分組成。一個完全符合CommonJS規(guī)范的包結(jié)構(gòu)應(yīng)包含以下文件:
1).package.json:包描述文件
2).bin:存放可執(zhí)行二進(jìn)制文件的目錄
3).lib:存放Javascript代碼的目錄
4).doc:存放文檔的目錄
5).test:存放單元測試用例的目錄
4.2 包描述文件
包描述文件是一個JSON文件——package.json,位于包的根目錄下,是包的重要組成部分,用于描述包的概況信息。后面要提到的NPM的所有行為都與這個文件的字段息息相關(guān)。下面將以知名Web框架express項目的package.json文件為例說明一些常用字段的含義。
1).name:包名
2).description:包簡介
3).version:版本號,需遵照“語義化的版本控制”,參照http://semver.org/
4).dependencies:使用當(dāng)前包所需要依賴的包列表。這個屬性十分重要,NPM會通過這個屬性自動加載依賴的包
5).repositories:托管源代碼的位置列表
其余字段的用法可以參照NPM package.json說明
4.3 NPM常用功能
NPM(node package manager),通常稱為node包管理器。它的主要功能就是管理node包,包括:安裝、卸載、更新、查看、搜索、發(fā)布等。
4.3.1 NPM包安裝
Node包的安裝分兩種:本地安裝、全局安裝。兩者的區(qū)別如下:
1).本地安裝npm install <package-name>:package會被下載到當(dāng)前所在目錄,也只能在當(dāng)前目錄下使用。
2).全局安裝npm install -g <package-name>:package會被下載到到特定的系統(tǒng)目錄下,安裝的package能夠在所有目錄下使用。
4.3.2 NPM包管理
下面以grunt-cli(grunt命令行工具)為例,列出常用的包管理命令:
1).npm install:安裝package.json文件的dependencies和devDependencies字段聲明的所有包
2).npm install grunt-cli@0.1.9:安裝特定版本的grunt-cli
3).npm install grunt-contrib-copy --save:安裝grunt-contrib-copy,同時保存該依賴到package.json文件
4).npm uninstall grunt-cli:卸載包
5).npm list:查看安裝了哪些包
6).npm publish <folder>:發(fā)布包
相關(guān)文章
Node.js安裝詳細(xì)步驟教程(Windows版)詳解
這篇文章主要介紹了Node.js安裝詳細(xì)步驟教程(Windows版),本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09node.js+jQuery實現(xiàn)用戶登錄注冊AJAX交互
本篇文章主要介紹了用Node.js當(dāng)作后臺、jQuery寫前臺AJAX代碼實現(xiàn)用戶登錄和注冊的功能的相關(guān)知識。具有很好的參考價值。下面跟著小編一起來看下吧2017-04-04Node 搭建一個靜態(tài)資源服務(wù)器的實現(xiàn)
這篇文章主要介紹了Node 搭建一個靜態(tài)資源服務(wù)器的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Node.js成為Web應(yīng)用開發(fā)最佳選擇的原因
本篇文章給大家詳細(xì)分析了Node.js 成為 Web 應(yīng)用開發(fā)最佳選擇的十個原因,對此有需要的朋友參考下。2018-02-02