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