- 核心工作原理
- 模組解析過程(Module Resolve)
- 模組物件(Module Object)
- 模組包裝(Module Wrapper)
- 快取(Cache)
- 迴圈引用(Cycle)
核心工作原理
模組解析過程(Module Resolve)
test.js
require('x')
複製程式碼
- x是node核心模組(如http,zlib等)則返回,否則繼續
- 根據Module物件的paths屬性一直遞迴找
node_modules
資料夾下是否存在該模組,直到根目錄,否則丟擲Error('MODULE_NOT_FOUND') - x是路徑(如/path/to/file)
- 嘗試LOAD_AS_FILE(如.js,.json,.node),沒有則繼續
- 嘗試LOAD_AS_DIR(如資料夾下package.json),沒有則丟擲Error('MODULE_NOT_FOUND')
LOAD_AS_FILE:
.js
.json
.node
檔案(編譯好的二進位制node外掛)
LOAD_AS_DIR:
X/package.json
中的main欄位作為模組入口檔案index.js
index.json
index.node
模組物件
Module {
id: '.',
exports: {},
parent: null,
filename: '/Users/wl/Sites/myapp/node-learning/src/module/index.js',
loaded: false,
children:
[
Module
{
id: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
exports: [Object],
parent: [Circular],
filename: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
loaded: true,
children: [Array],
paths: [Array]
}
],
paths:
[
'/Users/wl/Sites/myapp/node-learning/src/module/node_modules',
'/Users/wl/Sites/myapp/node-learning/src/node_modules',
'/Users/wl/Sites/myapp/node-learning/node_modules',
'/Users/wl/Sites/myapp/node_modules',
'/Users/wl/Sites/node_modules',
'/Users/wl/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
複製程式碼
id
模組id。通常為模組檔案絕對
路徑,主模組通常為.
exports
模組匯出物件。這裡的exports指的是module.exportsparent
父模組。即被依賴模組filename
模組檔名。通常與id
相同loaded
模組載入狀態。是否已執行完成children
子模組。即依賴模組paths
模組查詢路徑陣列。
模組包裝(Module Wrapper)
主要由以下兩點考慮
- 使模組內定義的頂層變數限制在方法(也就是wrapper或者說模組內部)級作用域中,防止汙染global環境
注:建議啟用'use strict'模式,防止定義全域性變數
- 傳入
module
,require
有利於實現node模組化機制
(function(exports, require, module, __filename, __dirname) {
// Module code
});
複製程式碼
快取(Cache)
在一個node上下文環境中,兩次require
同一個檔案,通常
情況下返回完全相同的兩個物件引用。除非用高階函式返回工廠函式。
迴圈引用(Cycle)
由於node包相互依賴,則較大可能會形成迴圈引用
,node利用其快取
機制避免無限迴圈。比如
index.js
const prefix = '主模組:'
const a = require('./a.js')
console.log(prefix, a) // {a:2}
console.log(prefix, require.main === module)
console.log(module)
複製程式碼
a.js
'use strict'
const prefix = 'A模組:'
module.exports = {a:1}
const b = require('./b.js')
console.log(prefix, b) // {b:1}
module.exports = {a:2}
console.log(prefix, require.main === module)
複製程式碼
b.js
const prefix = 'b模組:'
module.exports = {b:1}
const a = require('./a.js')
console.log(prefix, a) // {a:1}
console.log(prefix, require.main === module)
複製程式碼
如上。當b.js引用a.js時,為避免無限迴圈,a.js未完成的副本
(我認為是require('./b.js')之前的所有程式碼,但是在官方文件中未得到特別確切的表述)匯出的物件被b.js引用