Node.js 中的模块循环依赖
modules_cycles
When there are circular require() calls, a module might not have finished executing when it is returned.
当有循环的require调用时,模块返回时可能尚未完成它的执行
// a.js
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
// b.js
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
// main.js
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
result:

When main.js loads a.js, then a.js in turn loads b.js. At that point, b.js tries to load a.js. In order to prevent an infinite loop, an unfinished copy of the a.js exports object is returned to the b.js module. b.js then finishes loading, and its exports object is provided to the a.js module.
翻译:当 main.js 加载 a.js 时, a.js 又加载 b.js。 此时, b.js 会尝试去加载 a.js。 为了防止无限的循环,会返回一个 a.js 的 exports 对象的 未完成的副本 给 b.js 模块。 然后 b.js 完成加载,并将 exports 对象提供给 a.js 模块。
简单的说就算,为了防止模块载入的死循环,Node.js在模块第一次载入后会把它的结果进行缓存,下一次再对它进行载入的时候会直接从缓存中取出结果,所以在这种循环依赖情形下,不会有死循环。
为什么不会无限循环引用分析
执行node main.js :
- require('./a.js');此时会调用 self.require(), 然后会走到module._load,在_load中会判断./a.js是否被load过,当然运行到这里,./a.js还没被 load 过,所以会走完整个load流程,直到_compile。
- 运行./a.js,运行到 exports.done = false 的时候,给 esports 增加了一个属性。此时的 exports={done: false}。
- 运行require('./b.js'),同 第 1 步。
- 运行./b.js,到require('./a.js')。此时走到_load函数的时候发现./a.js已经被load过了,所以会直接从_cache中返回。所以此时./a.js还没有运行完,exports = {done.false},那么返回的结果就是 in b, a.done = false。
- ./b.js全部运行完毕,回到./a.js中,继续向下运行,此时的./b.js的 exports={done:true}, 结果自然是in main, a.done=true, b.done=true。
其它
虽然缓存解决了死循环的问题,但是大部分情况下我们不会这么写,而且这并没有解决正确导入模块的问题,所以,接下来看import,export📚。
参考
- modules_cycles
Node.js 中的模块循环依赖
modules_cycles
当有循环的require调用时,模块返回时可能尚未完成它的执行
result:

翻译:当 main.js 加载 a.js 时, a.js 又加载 b.js。 此时, b.js 会尝试去加载 a.js。 为了防止无限的循环,会返回一个 a.js 的 exports 对象的 未完成的副本 给 b.js 模块。 然后 b.js 完成加载,并将 exports 对象提供给 a.js 模块。
简单的说就算,为了防止模块载入的死循环,Node.js在模块第一次载入后会把它的结果进行缓存,下一次再对它进行载入的时候会直接从缓存中取出结果,所以在这种循环依赖情形下,不会有死循环。
为什么不会无限循环引用分析
执行node main.js :
其它
虽然缓存解决了死循环的问题,但是大部分情况下我们不会这么写,而且这并没有解决正确导入模块的问题,所以,接下来看import,export📚。
参考