在node.js documentation regarding module caching中,发出以下声明:
多次调用require('foo')可能不会导致模块代码多次执行。这是一个重要的特征。有了它,就可以返回“部分完成”对象,从而允许加载传递依赖,即使它们会导致循环。
我对最后一句话感到有点困惑。什么是“部分完成”的对象?这与允许(或避免)周期性依赖关系有何关系?
答案 0 :(得分:5)
如果你require
来自文件的一个包,并且导致该包中的文件require
导致初始require
的文件,那么你就会有一个循环依赖。默认情况下,它 只会进入圈子。为了防止这种情况,我们可以在原始require
开始处保留一个标记,以便下次该文件为require
时,它将从该点而不是从头开始。它并不完美,但在加载包装的情况下,您通常只对出口感兴趣,并且在这种情况下效果很好。
我推迟了a diff for node-browserify一段时间用于“部分完成”导出的原始方法。基本上,每次出现require
时,它都会检查出口量。如果有更多的导出,则意味着最后一次包不完整,并且仍然可以处理。如果没有新的导出(新旧计数相等),则表示包已完成,并且可以缓存,以便模块代码不会多次执行。因为它在浏览器中,所以无法控制执行流程,因此模块代码将部分重复(逐步)直到完成。虽然我确信Node.js的处理更加优雅。
答案 1 :(得分:1)
node.js documentation中提供了一个很好的明确示例。它更多地阐明了"部分完成"对象和循环依赖。
当有循环的require()调用时,模块在返回时可能没有完成执行。
考虑这种情况:
<强> a.js:强>
import componentStyles from './app-header.component.scss'
<强> b.js:强>
styles: [componentStyles]
<强> main.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');
当main.js加载a.js时,a.js依次加载b.js.此时,b.js尝试加载a.js.为了防止无限循环,a.js导出对象的未完成副本将返回到b.js模块。然后b.js完成加载,并将其exports对象提供给a.js模块。
当main.js加载了两个模块时,它们都已完成。因此,该计划的结果将是:
节点main.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');