nodeJS循环引用

2019-12-26  本文已影响0人  Minato666

最近在nodejs上由于一个exports使用方式方式不对导致在两个不同js循环引用的情况下导致其中一个js无法获取另外一个js的方法,从而导致执行报错,于是就去研究了一下nodeJs的循环引用。
官方给出了一个例子:

exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
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');
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);

上面可以看到在a.js中requireb.js, b.js中也require了a.js,两者是循环引用, 当执行main.js的时候输出如下:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true

main.js首先会load a.js, 此时执行到const b = require('./b.js');的时候,程序会转去loadb.js, 在b.js中执行到const a = require('./a.js');,为了防止无限循环,将a.jsexports的未完成副本返回到b.js模块。然后b.js完成加载,并将其导出对象提供给a.js模块。

我们知道nodeJs的对每个js文件进行了一层包装称为module,module中有一个属性exports,当调用require('a.js')的时候其实返回的是module.exports对象,module.exports初始化为一个{}空的object,所以在上面的例子中,执行到b.jsconst a = require('./a.js');时不会load新的a module, 而是将已经load但是还未完成的a module的exports属性返回给b module,所以b.js拿到的是a module的exports对象,即:{done:false}, 虽然在a.js中exports.done被修改成了true,但是由于此时a.js未load完成,所以在b.js输出的a module的属性done为false,而在main.js中输出的a module的属性done为true. Nodejs通过上面这种返回未完成exports对象来解决循环引用的问题。

上一篇 下一篇

猜你喜欢

热点阅读