a.js和b.js是如何相互依赖的?——CommonJS模块探索学习Node.js遇到2个模块相互引用的问题,有点迷糊。我觉得这个模块机制对于学习Node.js,搞清楚代码执行顺序是非常有必要的。所以在阅读了相关资料并实践之后,很高兴在这里分享成果。CommonJS中模块的“循环引用”问题先下结论:在CommonJS的实践中,一旦一个模块发生“循环引用”,也就是模块还没有被加载,就进入了循环,所以原理是只有出口已被执行。未执行的部分不输出。看不懂也没关系。我也没有第一次得到它。不过看这个例子就明白了~a.jsmodule.exports.done=falsevarb=require('./a.js')console.log(`Inmodulea,b.done=${b.done}`)module.exports.done=trueconsole.log('一个模块被执行')b.jsmodule.exports.done=falsevarb=require('./a.js')console.log(`在一个模块中,b.done=${b.done}`)module.exports.done=trueconsole.log('一个模块执行完成')在终端执行nodea.js。下面梳理一下代码的执行过程。然后自己跑代码验证一下~1.a模块第一行exportsdone=false;2.第二行requires('./b.js'),于是a模块暂停,进入并执行b模块3.b模块第一行exportsdone=false,然后require('./a.js'),此时出现“死循环”。关键是CommonJS将如何处理它?请看上面的结论,这里的a模块还没有执行,只执行了一句module.exports.done=false,所以导出的就是这个。4、b模块执行完后,跳回到a模块的第三行,然后依次打印。终端的结果,所以问题的关键是弄清楚当a模块还没有执行时,如果requireb模块中的a模块,执行时会导出a模块已经执行的部分.在上面的例子中,模块a只执行module.exports.done=false所以它导出了这个。那我建议同学们,试试把require('./b.js')放在第一行,看看执行结果会不会不一样?如果有的同学练习后还是不明白,可以看看参考资料里阮一峰老师的文章,或者看看我文章的第二部分。也许您缺乏CommonJS的其他一些知识。CommonJS需要知道的一些知识点知识点1:require('./a.js')时,不只是引用方法,如果是第一个require,会直接执行a.js知识点2:再次require('./a.js')没有重复执行a.js的bug,而是直接从缓存中取值。对于缓存的模块,通过require.cache可以看到知识点3:module.exports和exports的区别//简单的说,require只识别module.exports,//而exports是在初始化时对module.exports的引用exports=Module.exports知识点4:如果CommonJS中出现“循环引用”,会导出已经执行过的部分。ES6中如果出现“循环引用”,每次导入只生成一个模块引用,不影响变量的使用。CommonJS中“循环引用”的解决方法+方法一:module.exports=()=>{constmoduleDemo=require('./b.js')}require时避免直接执行,导致延迟。+方法二:在第一行提到module.exports,但不是万能的,因为要导出的东西可能依赖于文件下面的计算会有“循环引用”,只是执行方式不一样。因为以后会淘汰AMD和CMD规范,ES6和CommonJS值得研究。ES6的导入命令是import,例如import{foo}from'./some.js'ES6导入foo时,不会执行./some.js,而是生成模块的引用。当需要foo变量时,取some模块中的值。所以ES6是动态引用,不会缓存some.js,而是生成一个引用对象。导入时不要加载。自然,所谓的“循环引用”不是问题。参考文献http://www.ruanyifeng.com/blo...
