nodejs

150 阅读2分钟

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文件的第四行时;

image.png

  • require对象有一个cache对象;
  • cache里面有一个a模块和一个b模块(a.js文件的绝对路径和b.js文件的绝对路径作为对象的key);

image.png

  • a模块有一个children数组,有一个值是b模块;
  • a模块的Loaded是false;
  • a模块的exports是{},因为a.js还没有执行完;

image.png

  • b模块有一个children数组,有一个值是a模块;
  • b模块有一个parent对象,值是a模块;
  • b模块的Loaded是true;
  • b模块的exports如下截图:

image.png

输出结果:

b调用a {}
a调用b { xx: 111, yy: 222, zz: 333 }

步骤

  1. 路径解析:根据模块表示找出对应模块文件的绝对路径;
    • 根据文件的绝对路径查找cache缓存对象中是否存在
    • 尝试匹配原生模块
    • 未命中缓存,也没匹配到原生模块,就创建一个Module实例
  2. 缓存: 文件的绝对路径作为key缓存到一个对象中;value是一个Module实例,此时Module还是空的;
  3. 加载: 如果是JSON或JS文件,就把文件内容读入到内存。如果是内置的原生模块,将其共享库动态链接到当前Node.js进程;
  4. 包装: 将文件内容(JS代码)包进一个函数,建立模块作用域,exports、require、module等作为参数注入;
  5. 执行: 传入参数,执行包装得到的函数;执行代码的过程中,Module对象里面会一步步增加内容。
    • 如果加载/执行出错了,就删掉花村

循环依赖

上叙举例就是一个循环依赖,a模块引用b模块,b模块引用a模块;

  1. 首先缓存、加载、执行a.js
  2. a.js执行到require('./b.js')时,开始缓存、加载、执行b.js;
  3. b.js执行require('./a.js')时,直接从缓存中获取a模块的exports,输出a为{},a.x此时为undefined。
  4. b.js继续执行,执行完成后b的exports对象置为{ xx: 111, yy: 222, zz: 333 }
  5. 回到a.js,输出b = { xx: 111, yy: 222, zz: 333 }
  6. 继续执行a.js。

node模块查找规则