node的模塊機制

CommonJS承擔了拯救者的角色

在ES2015規範以前,JavaScript這門語言自己沒有提供組織代碼的方式, Node.js用CommonJS模塊規範填補了這個空白,在這篇文章裏面, 咱們將會討論node.js的模塊機制以及如何在項目中組織模塊javascript

模塊是什麼

模塊是代碼結構的基本構建單元,模塊容許你組織你本身的代碼,隱藏私有數據,經過module.exports暴露公共接口,每當你調用require的時候,你就在加載一個模塊vue

這是一個很簡單的使用CommonJS的例子java

// multiply.js
function multiply(a, b) {
    return a * b
}
module.exports = multiply
複製代碼

這個multiply.js文件就是一個模塊,要想使用它,咱們只須要require它便可node

const multiply = require('multiply')
    console.log(multiply(2, 3)) // 6
複製代碼

在背後,multiply.js被node.js用下面的方式包裝了npm

(function (exports, require, module, __filename, __dirname) {
 function multiply(a, b) {
    return a * b
}

  module.exports = add
})
複製代碼

這就是爲何你能夠在你的代碼中獲取到像require和module這些全局變量,模塊機制也保證了變量的做用域限制在本地而不會暴露到全局緩存

Node的模塊實現

在Node中引入模塊,須要經歷以下3個步驟。
路徑分析
文件定位
編譯執行函數

在Node中,模塊分爲兩類:一類是Node提供的模塊,稱爲核心模塊;另外一類是用戶編寫的模塊,稱爲文件模塊。post

核心模塊在Node源代碼的編譯過程當中,編譯進了二進制執行文件。在Node進程啓動時,部分核心模塊就被直接加載進內存中,因此這部分核心模塊引入時,文件定位和編譯執行這兩個步驟能夠省略掉,而且在路徑分析中優先判斷,因此它的加載速度是最 快的。
文件模塊則是在運行時動態加載,須要完整的路徑分析、文件定位、編譯執行過程,速度比核心模塊慢。ui

node的模塊加載機制是在第一次調用requrie以後緩存模塊,以後這個模塊的調用都是從緩存中讀取,也就是每當你使用`require('a-module'), 你將會獲得a-module的同一個實例,這保證了模塊是單例的,同一個模塊無論require多少次,在應用中都保持一個狀態this

你能夠加載原生模塊,路徑引用來自你的文件系統或者已經安裝的模塊,若是傳給require函數的標識符不是一個原生的模塊也不是一個文件的引用('./../'),node.js將會查找已經安裝的模塊,他會遍歷你的文件目錄裏面的node_modules文件夾,來查找引用的模塊

處理模塊加載的是node的核心模塊是module.js,能夠在node倉庫的lib/module.js找到它,其中最重要的是函數_load_complie

Module._load

這個函數檢查當前的模塊是否是存在緩存中,若是在緩存中,則返回導出的對象

若是模塊是原生的,會傳入filename作參數,調用NativeModule.require()方法,返回結果

不然,這個函數爲文件建立一個新模塊而且將其保存在緩存中,返回導出對象,流程以下

Module._compile

編譯函數在隔離的做用域或者沙箱裏面運行文件,對這個文件暴露了require,module, exports這些幫助變量

如何在項目中組織模塊

在應用中,咱們在建立模塊的時候須要處理好內聚和耦合的平衡,最理想的場景就是實現高內聚低耦合

一個模塊要想實現高內聚就須要專一一個功能,低耦合意味着模塊不該該有全局或共享的狀態,他們應該僅經過傳遞參數來通信,這樣即便模塊被替換也不須要改動太多的代碼庫

建議像下面這樣單獨暴露命名的函數和常量

const COUNT_NUMBER = 0

function count () { /* ... */ }

module.exports = {
  COUNT_NUMBER,
  count
}
複製代碼

而不是暴露一個含有各類屬性的對象

const COUNT_NUMBER = 0

function count () { /* ... */ }
let obj = {COUNT_NUMBER, count}
module.exports = obj
複製代碼

如何處理模塊

有兩種主要的方式寫Node模塊

一種是硬編碼依賴,經過調用require,顯式地加載一個模塊到另一個模塊,這種是最多見的使用方法,這種方式咱們用node來管理模塊的生命週期,直接易懂,並且也方便調試

第二種是依賴注入的方式

這種方式在node的環境中不多使用,但它是一個頗有用的概念,依賴注入模式能夠下降模塊間的解耦,這種模式不是顯式爲模塊定義依賴,而是從外面接收,所以很容易用一個有一樣接口的模塊來替代

咱們用工廠模式建立一個依賴注入的模塊,來講明下這種方式

class Car {
    constructor (options) {
    this.engine = options.engine
  }

  start () {
    this.engine.start()
  }
}
function create (options) {
  return new Car(options)
}
module.exports = create
複製代碼

當咱們使用create這個方法的時候,只要傳遞的options有engine屬性,而且engine屬性實現了start方法就能夠了,換句話說,無論你是啥車,自行車也能夠,只要有引擎,而且引擎有啓動的方法,我就能夠生產一臺車,哪怕有一天你的車升級了,能夠在水上開,空中飛也不要緊,這個create模塊我依然不須要修改

往期推薦

nodejs進階系列

1 npm的使用和最佳實踐
2 手把手教你用npm發佈包

vue系列

和尤雨溪一塊兒進階vue
vue項目實現緩存的最佳方案

相關文章
相關標籤/搜索