CommonJS和ES6 Module分别如何处理循环依赖的问题?
前篇(CommonJS和ES6 Module的区别):https://juejin.cn/post/6959360326299025445
前言:一般来说工程中应该尽量避免循环依赖的产生,因为从软件设计的角度来说,单向的依赖关系更加清晰,而循环依赖则会带来一定的复杂度。
- 但工程的复杂度上升到足够规模时,就容易出现隐藏的循环依赖关系。简单来说,A和B两个模块之间是否存在直接的循环依赖关系是很容易被发现的。但实际情况往往是A依赖于B,B依赖于C,C依赖于D,最后绕了一大圈,D又依赖于A。当中间模块太多时就很难发现A和B之间存在着隐式的循环依赖。
 
实际代码举例
目录结构:
├── main.js├── bar.js├── aaa.js
commonjs 循环依赖的处理情况(注释内有解析)
// main.jsconst bar = require('./bar.js')console.log('当前是main.js内:', bar) // {}module.exports = '在main.js内'// bar.jsconst main = require('./main.js')console.log('当前是bar.js内:', main)module.exports = 'bar.js内'// 执行 node ./main.js , 输出:当前是bar.js内: {} // 解析:执行到bar.js内时,main.js还没有执行完,就没有东西导出,会默认导出空对象当前是main.js内: bar.js内
es6 module 循环依赖的处理情况(注释内有解析)
// main.jsimport bar from './bar.js'console.log('当前是main.js内:', bar)export default '在main.js内'// bar.jsimport main from './main.js'console.log('当前是bar.js内:', main)export default 'bar.js内'// 执行 webpack-dev-server xx 启服务去执行 入口是main.js , 输出:当前是bar.js内: undefined // 解析:编译到bar.js内时,main.js还没有编译完,就没有东西编译映射到main这个变量上去,就是undefined当前是main.js内: bar.js内
解决方法
只能用es6 module,因为只有他的值的动态映射的,可以得到变更的状态
核心思路
- es6 module导出的值是动态映射的
 - 用function包裹,让加载先不立即执行
 - 用一个变量,来解决重复调用的问题(闭包)
 
// main.js (为了打包方便,此处main.js只作为入口,aaa和bar循环依赖)import aaa from './aaa.js'aaa('main')// aaa.jsimport bar from './bar.js'function aaa (name) {console.log('当前是aaa.js内:', name)bar('aaa')}export default aaa// bar.jsimport aaa from './aaa.js'let time = falsefunction bar (name) {if (!time) {time = trueconsole.log('当前是bar.js内:', name)aaa('bar')}}export default bar// 执行 webpack-dev-server xx 启服务去执行 入口是main.js , 输出:当前是aaa.js内: main当前是bar.js内: aaa当前是aaa.js内: bar
参考《Webpack实战:入门、进阶与调优》(居玉皓)
