本文講下在node.js中加載模塊的順序,原文如下:
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with ‘./’ or ‘/’ or ‘../’
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW “not found”LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.json is a file, parse X.json to a JavaScript Object. STOP
4. If X.node is a file, load X.node as binary addon. STOPLOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for “main” field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text. STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon. STOPLOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = “node_modules” CONTINUE
c. DIR = path join(PARTS[0 .. I] + “node_modules”)
b. DIRS = DIRS + DIR
c. let I = I - 1
5. return DIRS
上面看不懂也沒關係,看下面:
require(‘x’)
可以加載 .js 文件 .json 文件 .note文件
x 只有兩種可能:
1.’http’ ‘express’ 這種不帶路徑的
2.’./aa.js’ ‘../bb’ ‘/cc/dd/ee/ff’ 這種帶路徑的
第一種情況:要麼是核心模塊,要麼是node_modules
文件夾下面的模塊。如果都不是就報錯
第二種情況:根據路徑去找文件 或 文件夾
文件好理解,這裏說下文件夾,比如 ‘../bb’。node.js 會在調用 require(‘../bb’) 文件的上層去找bb 文件夾,
找到後會找 package.json 文件,看此文件中 main: 的值,main: 指定了入口。如果沒有 package.json 文件或者 這個文件中就沒有main:
node會去找此文件夾下面的 index.js , index.json 或 index.node ,如果找到了,萬事大吉,找不到的話就報錯了。node.js實在無能爲力了。在第一種情況中關於 node_modules
下的文件查找也是同樣的道理,只不過,node 會一層層向上找 node_modules
文件夾,還找不到的話,會去安裝目錄裏面去找。
其實上面講的不全面,看下圖:
舉個相互依賴的例子,a 模塊 依賴 b 模塊, b 模塊同樣依賴 a 模塊:
a.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
在上面的例子中,main.js
首先加載 a.js
到緩衝區中,在 a.js
中又會去加載 b.js
,b.js
在加載過程中又會去加載 a.js
。node.js 爲了防止這種死循環,不會再去加載 a.js
而是從緩衝區中讀取沒有加載完成的 a.js
模塊給 b.js
用,等 b.js
加載完成後再去加載a.js
中剩下的代碼塊。所以,node main.js
的輸出是:
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true