nodejs模塊整理

前言

模塊對於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

  1. require(模塊引用) => 這是整個模塊系統最核心的部分,可以引入其餘模塊,充分的運用。
  2. exports(模塊定義) => 另外一個出彩的地方,能夠將自身模塊中的內容導出,供其餘模塊使用。
  3. 標識(模塊標識) => 供別人認清楚模塊的東西。

這三塊內容可使用一張圖片歸納:github

如圖:npm

module

從這幅圖中,咱們能夠看到,模塊之間能夠經過exports將接口暴露出來,而後經過require來對另外一個模塊內的內容進行引入。編程

這樣咱們就大概懂得了模塊的定義。它主要分爲三部分:模塊的引用、模塊定義和模塊標識。json

然而,整個模塊部分咱們最須要去了解的是require機制。node對於require實現,有不少的東西能夠去欣賞。windows

首先,須要明白的是整個模塊引入的步驟。從上面的例子中,能夠看出這三部分:

  1. 路徑分析 => 拿例子來進行分析的話,'./circle'就是路徑。(./此類的是相對路徑,固然還有絕對路徑)
  2. 文件定位 => 經過分析出來的位置,去進行文件的獲取。
  3. 編譯執行 => 只有經過編譯過的文件,纔可以放入其餘模塊中進行使用 (以後也會分析如何進行編譯的)。

有的時候,狀況是特殊的。模塊自己就分紅核心模塊和文件模塊。而核心模塊在node源代碼編譯的時候。就被編譯成二進制文件。而且部分核心模塊會在node進程啓動時,直接加載到內存中,所以這一部分的核心模塊引入是不須要通過文件定位和編譯執行的步驟的。

還有特殊就是在緩存部分。每一個模塊首次加載以後,node會緩存其編譯執行後的對象,方便二次加載。因此,二次加載時,是以緩存優先的,從緩存中加載的模塊也是不須要文件定位和編譯的。

單從路徑分析提及,能夠分紅三種不一樣的方式:

  1. 核心模塊,如http、fs、path等,加載優先級僅次於緩存加載,且會直接編譯成二進制文件
  2. 路徑形式的模塊,如上面例子中的‘./circle’。路徑明確,查找速度相對較快,加載速度慢於核心模塊
  3. 自定義模塊,大多如npm包形式的文件,存儲在node_modules,並無相應的路徑。這種查找比較繁瑣。

查找方式: 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

最後就是模塊編譯部分的分析了:

首先,編譯執行也能夠經過上面的三類後綴文件名來進行分析:

  1. js文件 => 經過fs模塊同步讀取以後,編譯執行
  2. node文件 => .node文件是c/c++文件模塊的編譯文件,使用dlopen的方法對文件進行加載引入。
  3. json文件 => json文件首先是經過fs讀取文件,而後經過JSON.parse方法進行編譯執行。
    其餘後綴名的文件,都會被當成是js文件進行處理。同時,咱們須要的細緻地分析一下javascript文件編譯的一些具體過程。

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博客

相關文章
相關標籤/搜索