Require加載module機制詳解
-
-
- 加載檔案類型
- 加載流程圖
- 加載檔案詳細過程
- 加載module詳細過程
- 示例
-
加載檔案類型
node中的檔案和子產品是一一對應的。一個node.js檔案就是一個子產品,但是這個檔案可能是js代碼,JSON或者編譯過的C/C++拓展
加載流程圖
加載順序和流程如下圖所示,已經加載過的檔案會直接緩存起來,下次再require會直接從緩存加載。
加載檔案詳細過程
-
如果 X 是内置子產品
a. 傳回内置子產品
b. 停止執行
-
如果 X 以 ‘/’ 開頭
a. 設定 Y 為檔案根路徑
-
如果 X 以 ‘./’ 或 ‘/’ or ‘…/’ 開頭
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
- LOAD_NODE_MODULES(X, dirname(Y))
- 抛出異常 “not found”
LOAD_AS_FILE(X)
- 如果 X 是一個檔案, 将 X 作為 JavaScript 文本載入并停止執行。
- 如果 X.js 是一個檔案, 将 X.js 作為 JavaScript 文本載入并停止執行。
- 如果 X.json 是一個檔案, 解析 X.json 為 JavaScript 對象并停止執行。
- 如果 X.node 是一個檔案, 将 X.node 作為二進制插件載入并停止執行。
LOAD_AS_DIRECTORY(X)
-
如果 X/package.json 是一個檔案,
a. 解析 X/package.json, 并查找 “main” 字段。
b. let M = X + (json main 字段)
c. LOAD_AS_FILE(M)
d. LOAD_INDEX(M)
- LOAD_INDEX(X)
LOAD_INDEX(X)
- 如果 X/index.js 是一個檔案, 将 X/index.js 作為 JavaScript 文本載入并停止執行。
- 如果 X/index.json 是一個檔案, 解析 X/index.json 為 JavaScript 對象并停止執行。
- 如果 X/index.node 是一個檔案, 将 X/index.node 作為二進制插件載入并停止執行。
加載module詳細過程
-
查找目前目錄下面的node_modules目錄
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
- 如果沒找到,再查詢父目錄的node_modules目錄,直到找到或者到了根目錄的node_modules目錄(待查詢目錄在module對象裡面的paths數組中)
示例
const demo1 = require('./demoModule/demo');
// ./demoModule/demo => console.log('demo file whitout .js')
// ./demoModule/demo.js => console.log('demo file whit .js')
const demo2 = require('./demoModule/demoWithJson');
// {
// "memo": "this is json file"
// }
console.log(demo2.memo)
const demo3 = require('./demoModule/demoWithJS');
// ./demoModule/demoWithJS => console.log('demo file whit .js')
// ./demoModule/demoWithJS.json =>
// {
// "memo": "this is demoWithJS.json"
// }
const demo4 = require('./demoModule');
// ./demoModule/index.js => console.log('this is index.js in demoModule')
const demo5 = require('./demoModule/dirWithPackage');
// ./demoModule/dirWithPackage/main.js => console.log('this is main.js in dirWithPackage')
// ./demoModule/dirWithPackage/package.json 裡面的main字段為“main.js”
// const demo6 = require('./demoModule/demoNode');
const demo7 = require('demo')
/*
./node_modules/demo/index.js
// 源碼:
console.log('this is index.js in node_modules/demo')
const subDemo = require('subdemo');
const subDemo2 = require('subdemo2');
// subdemo 和 subdemo2所在位置和源碼
./node_modules/demo/node_modules/subdemo/index.js
=> console.log('this is index.js in ./node_modules/demo/node_modules/subdemo')
./node_modules/subdemo2/index.js
=> console.log('this is index.js in ./node_modules/subdemo2')
*/
const demo8 = require('demo2')
// ./node_modules/demo2/index.js => console.log('this is index.js in ./node_modules/demo2')
// ./node_modules/demo2.js => console.log('this is demo2.js in ./node_modules')
const subDemo3 = require('subdemo3');
// ../node_modules/subdemo3/index.js
const subDemo4 = require('subdemo4');
// ../../node_modules/subdemo4/index.js
const subDemo5 = require('subdemo5');
// /Users/username/.node_modules/subdemo5.js
輸出結果
demo file whitout .js
this is json file
demo file whit .js
this is index.js in demoModule
this is main.js in dirWithPackage
this is index.js in node_modules/demo
this is index.js in node_modules/demo/node_modules/subdemo
this is index.js in node_modules/subdemo2
this is demo2.js in ./node_modules
this is index.js in …/node_modules/subdemo3
this is index.js in …/…/node_modules/subdemo4
this is subdemo5.js in /Users/lifugui/.node_modules
其實,module.paths 裡面已經包含了上述這些會去查找的目錄以及優先級
// 目前檔案目錄 /Users/username/Documents/projects/nodeDemo
[
'/Users/username/Documents/projects/nodeDemo/repl/node_modules', // 這個目錄是幹嘛的?不清楚,實測并不會從這個目錄加載module
'/Users/username/Documents/projects/nodeDemo/node_modules',
'/Users/username/Documents/projects/node_modules',
'/Users/username/Documents/node_modules',
'/Users/username/node_modules',
'/Users/node_modules',
'/node_modules',
'/Users/username/.node_modules', // 全局module 可以考慮放這兩個目錄
'/Users/username/.node_libraries'
]