模塊對於node來講是不可或缺的一部分,是服務端編程的基礎。趁着整理模塊之際,先將node部分的模塊的封裝等作一個總結。但願可以切實的幫助到你。本篇將對CommenJS規範,node的文件模塊和核心模塊等作一個綜合的整理。若是你喜歡個人文章,歡迎評論,歡迎Star~。歡迎關注個人github博客javascript
我以爲模塊的出現是js進步最大的地方。由於有了模塊,才使得不少優秀的東西能夠真正被共享出來,而不用去擔憂變量污染、命名空間的問題。java
node做爲一門服務端的javascript,它借鑑了CommonJS的規範,造成了一套易用的模塊規範。node
首先,看看下面這個最多見的例子:c++
//circle.js const { PI } = Math; exports.area = x => PI*x**2; exports.circle = x => 2*PI*x;
//main.js const circle = require('./circle'); console.log(circle.area(4)); //50.26548245743669
其實,咱們能夠清晰地看到兩個文件中,模塊規範部分能夠分紅三部分:git
這三塊內容可使用一張圖片歸納:github
如圖:npm
從這幅圖中,咱們能夠看到,模塊之間能夠經過exports將接口暴露出來,而後經過require來對另外一個模塊內的內容進行引入。編程
這樣咱們就大概懂得了模塊的定義。它主要分爲三部分:模塊的引用、模塊定義和模塊標識。json
然而,整個模塊部分咱們最須要去了解的是require機制。node對於require實現,有不少的東西能夠去欣賞。windows
首先,須要明白的是整個模塊引入的步驟。從上面的例子中,能夠看出這三部分:
有的時候,狀況是特殊的。模塊自己就分紅核心模塊和文件模塊。而核心模塊在node源代碼編譯的時候。就被編譯成二進制文件。而且部分核心模塊會在node進程啓動時,直接加載到內存中,所以這一部分的核心模塊引入是不須要通過文件定位和編譯執行的步驟的。
還有特殊就是在緩存部分。每一個模塊首次加載以後,node會緩存其編譯執行後的對象,方便二次加載。因此,二次加載時,是以緩存優先的,從緩存中加載的模塊也是不須要文件定位和編譯的。
單從路徑分析提及,能夠分紅三種不一樣的方式:
查找方式: 1. 從當前目錄下面的node_modules中查找是否具有相應的模塊 2. 若具有,則直接加載使用,不然,會去查找父目錄下的node_modules目錄,直至查找到根目錄下的node_modules中。這種方式是最慢的。
再來分析文件定位:
第一個例子中的標識符是'./circle'。能夠發現,這個文件標識符是沒有後綴名的。那麼,node是如何來進行定位的呢?其實,node有一個默認的定位順序:js、node、json。這裏會最早識別js,以後一次對json和node的文件進行識別。所以,這裏有個小技巧:在識別.node和.json的文件的時候,帶上文件後綴名會快一點, 爲何呢?是由於,node是使用fs同步阻塞的方式,逐一去嘗試,該文件是否存在,存在着直接加載;不存在的話,嘗試下一個後綴名。
還有對於那些自定義的模塊,如npm包。node的定位方式也是不一樣的。一般來講,npm包中都會具有package.json文件,這個文件中有個main屬性,這指向的就是整個包的入口文件;若是沒有這些條件,node會去默認加載index.js、index.json和index.node
最後就是模塊編譯部分的分析了:
首先,編譯執行也能夠經過上面的三類後綴文件名來進行分析:
javascript文件編譯
在使用fs讀取文件以後,讀取出來的內容node會如何去處理呢?會形成變量污染嗎?很顯然是不會的。node是根據CommonJS的規範,對讀取進入的內容,在頭部和尾部進行包裝,包裝成function(exports, require, module, __dirname,__filename){ ...讀取內容 }。這樣子,就起到了一個做用域隔絕的做用,不會對現有模塊中的內容污染。而__dirname、__filename是node中存在的。
而後將這個函數代碼使用vm原生的模塊runInThisContext()方法執行(相似eval => 將字符串轉化成可執行的js的代碼)。而後返回一個具體的對象,供現有模塊中的內容進行使用。
C/C++模塊的編譯
這個編譯主要是依靠node的process.dlopen()方法進行執行,同時node使用libuv對windows和*nix平臺作了兼容性的處理。這種模塊的性能相對於普通文件模塊來講較高,可是編寫成本也會相應地提升。
json文件編譯
json文件編譯會比較簡單,就是經過fs讀取文件,而後經過JSON.parse方法進行編譯,最終將內容給予現有模塊中命名的那個變量。
至此咱們對node的模塊總體的機制,大體已經整理清楚了,從模塊的導出,到引入,以及標識符的分析。都可從CommonJS中找到影子,可是node對其進行的加工又相對比較完美。
若是你對我寫的有疑問,能夠評論,如我寫的有錯誤,歡迎指正。你喜歡個人博客,請給我關注Star~呦。你們一塊兒總結一塊兒進步。歡迎關注個人github博客