node事件循环机制
node模块加载机制
require()时发生了什么?
举例
a.js文件
var x = 11;
var b = require('./b')
console.log('a调用b',b)
var y = 22;
var z = 33
module.export = {x,y,z}
b.js文件
var xx = 111;
var a = require('./a')
console.log('b调用a',a)
var yy = 222;
var zz = 333;
module.exports = { xx,yy,zz }
执行到a.js文件的第四行时;
- require对象有一个cache对象;
- cache里面有一个a模块和一个b模块(a.js文件的绝对路径和b.js文件的绝对路径作为对象的key);
- a模块有一个children数组,有一个值是b模块;
- a模块的Loaded是false;
- a模块的exports是{},因为a.js还没有执行完;
- b模块有一个children数组,有一个值是a模块;
- b模块有一个parent对象,值是a模块;
- b模块的Loaded是true;
- b模块的exports如下截图:
输出结果:
b调用a {}
a调用b { xx: 111, yy: 222, zz: 333 }
步骤
- 路径解析:根据模块表示找出对应模块文件的绝对路径;
- 根据文件的绝对路径查找cache缓存对象中是否存在
- 尝试匹配原生模块
- 未命中缓存,也没匹配到原生模块,就创建一个Module实例
- 缓存: 文件的绝对路径作为key缓存到一个对象中;value是一个Module实例,此时Module还是空的;
- 加载: 如果是JSON或JS文件,就把文件内容读入到内存。如果是内置的原生模块,将其共享库动态链接到当前Node.js进程;
- 包装: 将文件内容(JS代码)包进一个函数,建立模块作用域,exports、require、module等作为参数注入;
- 执行: 传入参数,执行包装得到的函数;执行代码的过程中,Module对象里面会一步步增加内容。
- 如果加载/执行出错了,就删掉花村
循环依赖
上叙举例就是一个循环依赖,a模块引用b模块,b模块引用a模块;
- 首先缓存、加载、执行a.js
- a.js执行到require('./b.js')时,开始缓存、加载、执行b.js;
- b.js执行require('./a.js')时,直接从缓存中获取a模块的exports,输出a为{},a.x此时为undefined。
- b.js继续执行,执行完成后b的exports对象置为{ xx: 111, yy: 222, zz: 333 }
- 回到a.js,输出b = { xx: 111, yy: 222, zz: 333 }
- 继续执行a.js。