- 核心工作原理
- 模块解析过程(Module Resolve)
- 模块对象(Module Object)
- 模块包装(Module Wrapper)
- 缓存(Cache)
- 循环引用(Cycle)
核心工作原理
模块解析过程(Module Resolve)
test.js
require('x')
复制代码
- x是node核心模块(如http,zlib等)则返回,否则继续
- 根据Module对象的paths属性一直递归找
node_modules
文件夹下是否存在该模块,直到根目录,否则抛出Error('MODULE_NOT_FOUND') - x是路径(如/path/to/file)
- 尝试LOAD_AS_FILE(如.js,.json,.node),没有则继续
- 尝试LOAD_AS_DIR(如文件夹下package.json),没有则抛出Error('MODULE_NOT_FOUND')
LOAD_AS_FILE:
.js
.json
.node
文件(编译好的二进制node插件)
LOAD_AS_DIR:
X/package.json
中的main字段作为模块入口文件index.js
index.json
index.node
模块对象
Module {
id: '.',
exports: {},
parent: null,
filename: '/Users/wl/Sites/myapp/node-learning/src/module/index.js',
loaded: false,
children:
[
Module
{
id: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
exports: [Object],
parent: [Circular],
filename: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
loaded: true,
children: [Array],
paths: [Array]
}
],
paths:
[
'/Users/wl/Sites/myapp/node-learning/src/module/node_modules',
'/Users/wl/Sites/myapp/node-learning/src/node_modules',
'/Users/wl/Sites/myapp/node-learning/node_modules',
'/Users/wl/Sites/myapp/node_modules',
'/Users/wl/Sites/node_modules',
'/Users/wl/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
复制代码
id
模块id。通常为模块文件绝对
路径,主模块通常为.
exports
模块导出对象。这里的exports指的是module.exportsparent
父模块。即被依赖模块filename
模块文件名。通常与id
相同loaded
模块加载状态。是否已执行完成children
子模块。即依赖模块paths
模块查找路径数组。
模块包装(Module Wrapper)
主要由以下两点考虑
- 使模块内定义的顶层变量限制在方法(也就是wrapper或者说模块内部)级作用域中,防止污染global环境
注:建议启用'use strict'模式,防止定义全局变量
- 传入
module
,require
有利于实现node模块化机制
(function(exports, require, module, __filename, __dirname) {
// Module code
});
复制代码
缓存(Cache)
在一个node上下文环境中,两次require
同一个文件,通常
情况下返回完全相同的两个对象引用。除非用高阶函数返回工厂函数。
循环引用(Cycle)
由于node包相互依赖,则较大可能会形成循环引用
,node利用其缓存
机制避免无限循环。比如
index.js
const prefix = '主模块:'
const a = require('./a.js')
console.log(prefix, a) // {a:2}
console.log(prefix, require.main === module)
console.log(module)
复制代码
a.js
'use strict'
const prefix = 'A模块:'
module.exports = {a:1}
const b = require('./b.js')
console.log(prefix, b) // {b:1}
module.exports = {a:2}
console.log(prefix, require.main === module)
复制代码
b.js
const prefix = 'b模块:'
module.exports = {b:1}
const a = require('./a.js')
console.log(prefix, a) // {a:1}
console.log(prefix, require.main === module)
复制代码
如上。当b.js引用a.js时,为避免无限循环,a.js未完成的副本
(我认为是require('./b.js')之前的所有代码,但是在官方文档中未得到特别确切的表述)导出的对象被b.js引用