module : 在 node 中每一个 js 文件都是一个 module ,module 上除了保存了 exports 等信息,还有 loaded 表示该模块是否被加载:false表示没有加载,true 为已加载
Module : 以nodejs 为例 ,整个系统运行以后,会用 Module 缓存每一个模块加载的信息
require 大致流程:
1. require 会接收一个参数——文件标识符,然后分析定位文件,分析过程我们上述已经讲到了,加下来会从 Module 上查找有没有缓存,如果有缓存,那么直接返回缓存的内容。
2. 如果没有缓存,会创建一个 module 对象,缓存到 Module 上,然后执行文件,加载完文件,将 loaded 属性设置为 true ,然后返回 module.exports 对象。借此完成模块加载流程。
3. 模块导出就是 return 这个变量的其实跟 a = b 赋值一样, 基本类型导出的是值, 引用类型导出的是引用地址。
4. exports 和 module.exports 持有相同引用,因为最后导出的是 module.exports, 所以对 exports 进行赋值会导致 exports 操作的不再是 module.exports 的引用。
require 避免重复加载:
a.js
const getMes = require('./b.js')
console.log('我是 a 文件')
exports.say = function(){
const message = getMes()
console.log(message)
}
b.js
const say = require('./a.js')
const object = {
name: '李四',
author: '张三'
}
console.log('我是 b 文件')
console.log('打印 a 模块', say)
setTimeout(() => {
console.log('异步打印 a 模块', say)
}, 0)
module.exports = function () {
return object
}
main.js
const a = require('./a')
const b = require('./b')
console.log('node 入口文件')
运行 node main.js
main.js
和a.js
模块都引用了b.js
模块,但是b.js
模块只执行了一次。
a.js
模块 和b.js
模块互相引用,但是没有造成循环引用的情况。执行顺序是父 -> 子 -> 父;
1. 首先加载之后的文件的 module
会被缓存到 Module
上,比如一个模块已经 require 引入了 a 模块,如果另外一个模块再次引用 a ,那么会直接读取缓存值 module ,所以无需再次执行模块。
2. 从上可以看出,首先 main.js
引用了 a.js
,a.js
中 require 了 b.js
此时 b.js
的 module 放入缓存 Module
中,接下来 main.js
再次引用 b.js
,那么直接走的缓存逻辑。所以 b.js 只会执行一次,也就是在 a.js 引入的时候。