[摘抄] 5.模块的加载机制

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函数准备完毕,整个所要加载的脚本内容,就被放到一个新的函数之中,这样可以避免污染全局环境。该函数的参数包括requiremoduleexports,以及其他一些参数 。

(function (exports, require, module, __filename, __dirname) {
  // YOUR CODE INJECTED HERE!
});

Module._compile方法是同步执行的,所以Module._load要等它执行完成,才会向用户返回module.exports的值。

【end】

你可能感兴趣的:([摘抄] 5.模块的加载机制)