最近在nodejs上由于一個(gè)exports使用方式方式不對(duì)導(dǎo)致在兩個(gè)不同js循環(huán)引用的情況下導(dǎo)致其中一個(gè)js無(wú)法獲取另外一個(gè)js的方法,從而導(dǎo)致執(zhí)行報(bào)錯(cuò),于是就去研究了一下nodeJs的循環(huán)引用。
官方給出了一個(gè)例子:
- a.js:
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);
上面可以看到在a.js中requireb.js, b.js中也require了a.js,兩者是循環(huán)引用, 當(dāng)執(zhí)行main.js的時(shí)候輸出如下:
$ 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首先會(huì)load a.js, 此時(shí)執(zhí)行到const b = require('./b.js');的時(shí)候,程序會(huì)轉(zhuǎn)去loadb.js, 在b.js中執(zhí)行到const a = require('./a.js');,為了防止無(wú)限循環(huán),將a.jsexports的未完成副本返回到b.js模塊。然后b.js完成加載,并將其導(dǎo)出對(duì)象提供給a.js模塊。
我們知道nodeJs的對(duì)每個(gè)js文件進(jìn)行了一層包裝稱為module,module中有一個(gè)屬性exports,當(dāng)調(diào)用require('a.js')的時(shí)候其實(shí)返回的是module.exports對(duì)象,module.exports初始化為一個(gè){}空的object,所以在上面的例子中,執(zhí)行到b.js中const a = require('./a.js');時(shí)不會(huì)load新的a module, 而是將已經(jīng)load但是還未完成的a module的exports屬性返回給b module,所以b.js拿到的是a module的exports對(duì)象,即:{done:false}, 雖然在a.js中exports.done被修改成了true,但是由于此時(shí)a.js未load完成,所以在b.js輸出的a module的屬性done為false,而在main.js中輸出的a module的屬性done為true. Nodejs通過(guò)上面這種返回未完成exports對(duì)象來(lái)解決循環(huán)引用的問(wèn)題。