node中require的循环使用

我们在Node中可以通过require来很方便的引入一个模块,而且我们一直到require模块是一个同步的过程,那么当一个两个模块相互引用的时候,Node会如何处理呢?

在Node的官方文档中我们看到了如下的描述

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 模块。

那么这里的副本指的是什么呢?

我们通过下面这个例子输出exports 对象

a.js

1
2
3
4
5
6
const b = require('./b.js');

console.log(b.name);
console.log(b);
exports.name = 'a.js';
console.log(b.name);

b.js

1
2
3
4
5
const a = require('./a.js');
console.log(a.name);
console.log(a);
exports.name = 'b.js';
console.log(a.name);

当我们执行node a.js的时候输出

1
2
3
4
5
undefined
{}
undefined
b.js
b.js

所以我们可以看到Node会按照require模块的顺序,倒序加载模块,如果当前模块中出现了还未加载过的且依赖于当前模块,则将需要的模块的exports 对象默认为{}(空对象)来防止循环加载的问题。