5.模块的加载机制
CommonJS模块的加载机制是,输入的是被输出的值的拷贝,也就是说一旦输出一个值,模块内部的变化就影响不到这个值。
下面是一个模块文件 lib.js
// lib.js
var counter = 3;
function incCounter(){
counter ++;
}
module.exports = {
counter,
incCounter
}
上面代码输出内部变量counter
和改写这个变量的内部方法incCounter
。
然后加载上面的模块。
// main.js
var counter = require('./lib').counter;
var incCounter = require('./lib').incCounter;
console.log(counter) //3
incCounter();
console.log(counter) //3
上面代码说明,counter
输出以后,lib.js模块内部的变化就影响不到counter
了
# 5.1 require的内部处理流程
require
命令是CommonJS规范之中用来加载其他模块命令。
- 他其实不是一个全局命令,而是指向当前模块的
module.require
命令,而后者又调用Node的内部命令,Module._load
。
Module._load = function(request, parent, isMain) {
// 1. 检查 Module._cache,是否缓存之中有指定模块
// 2. 如果缓存之中没有,就创建一个新的Module实例
// 3. 将它保存到缓存
// 4. 使用 module.load() 加载指定的模块文件,
// 读取文件内容之后,使用 module.compile() 执行文件代码
// 5. 如果加载/解析过程报错,就从缓存删除该模块
// 6. 返回该模块的 module.exports
};
上面的第4步,采用module.compile()
执行指定模块的脚本,逻辑如下。
Module.prototype._compile = function(content, filename) {
// 1. 生成一个require函数,指向module.require
// 2. 加载其他辅助方法到require
// 3. 将文件内容放到一个函数之中,该函数可调用 require
// 4. 执行该函数
};
上面的第1步和第2步,require
函数及其辅助方法主要如下。
require()
: 加载外部模块require.resolve()
:将模块名解析到一个绝对路径require.main
:指向主模块require.cache
:指向所有缓存的模块require.extensions
:根据文件的后缀名,调用不同的执行函数
一旦require
函数准备完毕,整个所要加载的脚本内容,就被放到一个新的函数之中,这样可以避免污染全局环境。该函数的参数包括require
、module
、exports
,以及其他一些参数 。
(function (exports, require, module, __filename, __dirname) {
// YOUR CODE INJECTED HERE!
});
Module._compile
方法是同步执行的,所以Module._load
要等它执行完成,才会向用户返回module.exports
的值。
【end】