require 加載機制

本文講下在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. STOP

LOAD_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. STOP

LOAD_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 文件夾,還找不到的話,會去安裝目錄裏面去找。


其實上面講的不全面,看下圖:

require

舉個相互依賴的例子,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.jsb.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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章