require()循环引用问题

1、场景如下

例如a.js和b.js相互引用:
a.js内容为:

exports.done = false;

var b = require('./b.js');

exports.hello = false;

console.log(`在a中b.done的值为:`+b.done);

exports.done = true;复制代码

b.js内容为:

exports.done = false;

var a = require('./a.js');

console.log(`在b中a.done的值为:`+a.done);
console.log(`在b中a.hello的值为:`+a.hello);

exports.done = true;复制代码

在main.js引用a和b

var a = require('./a.js');
var b = require('./b.js');复制代码

问题如下

1、main.js引用了a.js,此时读取a.js里的数据
2、a.js运行时先把exports.done的值设为false,接着运行第二行,第二行开始加载b.js
3、b.js运行时,先把自己的exports.done的值设为false,然后加载a.js
问题来了,此时a.js是不是又开始加载,然后又遇到b.js,b.js加载又遇到a.js。。。。无限循环呢复制代码

结果肯定是不会无限循环,我们先把结果理出来,然后分析require函数里面什么样的功能避免了无限循环引用

结果如下:
1、main.js引用了a.js,此时读取a.js里的数据
2、a.js运行时先把exports.done的值设为false,接着运行第二行,第二行开始加载b.js
3、b.js运行时,先把自己的exports.done的值设为false,然后加载a.js
4、此时的a.js不会重新加载文件,而是导出一个对象,{ exports: done }(其它属性略去)
5、所以在b.js里面var a = { exports: done }(其它属性略去),然后继续执行
6、然后b.js console出两行分别是 
在b中a.done的值为:false
在b中a.hello的值为:undefined7、最后b.js把exports.done属性的值设为了true
8、接着回到a.js的第二行,var b = require('./b.js');此时b={ exports: true}(其它属性略去)
9、接着执行第三行exports.hello = false;,此时hello属性为false
10、执行第四行,打印出
在a中b.done的值为:true11、接着执行最后一行exports.done = true; 把自己的done属性又改为true复制代码

这里最让人困惑的就是上面的第四条,就是为什么a.js不会重新加载,而是导出一个对象呢

这是我之前转载的文章,关于require函数源码juejin.im/post/5c7b6e…

其中require你相当于看成如下函数(只关心第三步和第四步)

Module._load = function(request, parent, isMain) {

  //  计算绝对路径
  var filename = Module._resolveFilename(request, parent);

  //  第一步:如果有缓存,取出缓存
  var cachedModule = Module._cache[filename];
  if (cachedModule) {
    return cachedModule.exports;

  // 第二步:是否为内置模块
  if (NativeModule.exists(filename)) {
    return NativeModule.require(filename);
  }

  // 第三步:生成模块实例,存入缓存
  var module = new Module(filename, parent);
  /**注:Module实现如下
  *function Module(id, parent) {   *this.id = id;
   *this.exports = {};
   *this.parent = parent;
   *this.filename = null;
   *this.loaded = false;
   *this.children = [];
  *}
   **/  Module._cache[filename] = module;

  // 第四步:加载模块
  try {
    module.load(filename);
    hadException = false;
  } finally {
    if (hadException) {
      delete Module._cache[filename];
    }
  }

  // 第五步:输出模块的exports属性
  return module.exports;
};复制代码

注意第三步是先存入缓存,后加载模块,也就是说,模块只加载一次,后面的全用缓存的了,所以之前的a.js加载过一次之后,剩下的都是用缓存里的new Module(filename, parent)了

这个new Module是一个对象,里面包括exports属性,这个exports属性就是每个模块导出的属性,例如exports.done = false

本文结束


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值