学习Node.js遇到2个模块互相引用的问题,有点搞不清楚。我以为这个模块机制对于学习Node.js来讲,搞清代码执行顺序来讲,十分有必要。html
因此在读了相关资料,并实践以后,愉快的在这分享一下成果。node
先说结论: CommonJS中的作法时,一旦某个模块被”循环引用“,也就是这个模块没有加载完,就进入了循环,因此原则是, 只exports已经执行的那部分,没执行的不输出。
若是没看懂,不要紧。我第一遍也没明白。可是看下这个例子就好理解啦~缓存
a.js
module.exports.done = false var b = require('./a.js') console.log(`在a模块中,b.done=${b.done}`) module.exports.done = true console.log('a模块执行完毕')
b.js
module.exports.done = false var b = require('./a.js') console.log(`在a模块中,b.done=${b.done}`) module.exports.done = true console.log('a模块执行完毕')
在终端执行模块化
node a.js
下面咱们梳理代码的执行过程。而后本身运行代码验证一下就好啦~学习
终端的结果
因此问题的关键,就是弄清楚,当a模块还没执行完成时,b模块里require a模块的话,执会导出a模块已经执行完成的部分。ui
上面的例子中,a模块只执行了spa
module.exports.done = false
因此就导出了这个。code
那么建议同窗们,试一下把require('./b.js')放到第一行,试试看执行结果会有什么不一样?htm
若是有同窗实践后,仍是不理解的话,能够看看参考资料里阮一峰老师的文章,或者看一眼我这篇文章的第二个部分,也许缺乏一些CommonJS的其余知识。对象
被缓存的模块,能够经过require.cache里看到
// 简单说,require只认module.exports, // 而初始化时 exports是module.exports的引用 exports = module.exports
关于CommonJS里"循环引用"的解决方法 + 办法1:module.exports = () => {const moduleDemo = require('./b.js')} 避免require时直接执行,使其延迟执行。 + 办法2:把module.exports提到第一行,但不是万能的,由于要导出的东西可能依赖文件下面的计算
每个模块化方案,均可能会遇到"循环引用"的状况,可是执行方式不同。
由于AMD和CMD规范未来会被淘汰,因此ES6和CommonJS更值得拿出来研究一下。
ES6的引入命令是import,例如
import {foo} from './some.js'
ES6引入foo时,不会执行./some.js,而是生成一个该模块的引用,当须要用foo变量时,在到some模块里取值。
因此ES6是动态引用,不会缓存some.js,而是生成一个引用对象。
在import时不去加载。天然地,所谓"循环引用"也就不是问题了。