Node.js – 模块caching,部分完​​成的对象和循环依赖?

在关于模块caching的node.js文档中 ,做了以下说明:

多次调用require('foo')可能不会导致模块代码被多次执行。 这是一个重要的function。 有了它,“ 部分完成 ”的对象可以被返回,从而允许传递依赖被加载,即使它们会导致循环。

我对最后一句话有些困惑。 什么是“部分完成”的对象? 这与如何允许(或避免)周期性依赖关系有关?

如果您require文件中的包,并导致该包中的文件需要导致初始require的文件,则您具有循环依赖关系。 默认情况下,它只会循环。 为了防止这种情况发生,可以将标记保留在require启动的位置,以便下次该文件被require时,将从该点开始,而不是从开始。 这不是完美的,但在加载一个包的情况下,你通常只对出口感兴趣,并在这种情况下运作良好。

我为node-browserify推了一个diff,而后来又回到了“部分完成”导出的原始方法。 基本上,每次有require的东西都会检查出口量。 如果有更多的出口,这意味着上次包装不完整,仍然可能正在处理。 如果没有新的导出(新旧计数相等),则意味着程序包已经完成,并且可以被caching,以便模块代码不会被多次执行。 因为它在浏览器中,所以没有对执行stream程的控制,因此模块代码将被部分(分步)重复,直到完成。 而我确信Node.js有更优雅的处理。

在node.js文档中提供了一个很好的清晰的例子。它更清楚地说明了“部分完成”的对象和循环依赖关系。

当存在循环的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 exports对象的未完成副本返回给b.js模块。 b.js然后完成加载,并且它的exports对象被提供给a.js模块。

到main.js加载这两个模块的时候,他们都完成了。 这个程序的输出结果是:

节点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