循环


当有循环 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);

main.js 加载 a.js 时,a.js 依次加载 b.js。 此时,b.js 尝试加载 a.js。 为了防止无限循环,将 a.js 导出对象的未完成副本返回给 b.js 模块。 然后 b.js 完成加载,并将其 exports 对象提供给 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

需要仔细规划以允许循环模块依赖项在应用程序中正常工作。

When there are circular require() calls, a module might not have finished executing when it is returned.

Consider this situation:

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);

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.

By the time main.js has loaded both modules, they're both finished. The output of this program would thus be:

$ 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

Careful planning is required to allow cyclic module dependencies to work correctly within an application.