这篇文章的重点是讲解如何解决循环依赖的问题。如果你关心这个问题是怎么产生的,你可以自己谷歌一下。如何重现这个问题//a.jsconst{sayB}=require('./b.js')sayB()functionsayA(){console.log('sayA')}module.exports={sayA}//b.jsconst{sayA}=require('./a.js')sayA()functionsayB(){console.log('sayB')}module.exports={sayB}执行下面的代码?测试git:(master)?nodea.js/Users/dd/wj-gitlab/tools/test/b.js:3sayA()^TypeError:sayA不是Object.(/Users/dd/wj-gitlab/tools/test/b.js:3:1)在Module._compile(module.js:635:30)在Object.Module._extensions..js(module.js:646:10)在Module.load(module.js:554:32)在tryModuleLoad(module.js:497:12)在Function.Module._load(module.js:489:3)在Module.require(module.js:579:17)atrequire(internal/module.js:11:18)atObject.(/Users/dd/wj-gitlab/tools/test/a.js:1:78)atModule._compile(module.js:635:30)sayA不是函数那么sayA是什么?事实上,它是未定义的。当遇到这种问题时,你最好意识到它可能是一个循环依赖问题,否则找到问题可能会事倍功半。如何查找循环依赖文件上面的示例代码很简单,2个文件,很容易找到循环依赖。如果有十几个文件,要手动查找循环依赖的文件是很麻烦的。下面推荐一个工具madge,可以可视化文件之间的依赖关系。注意下图1,从cli.js开始,所有的箭头都向右展开,说明没有循环依赖。如果有向左向后流的箭头,则可能是循环依赖点。在图2中,出现了一个向左的箭头,说明发生了循环依赖,说明这里应该断环。[图1][图2]如何解决循环依赖方案一:先导出自己的模块并将module.exports放在文件头,先导出自己的模块,再导入其他模块。来自:http://maples7.com/2016/08/17...//a.jsmodule.exports={sayA}const{sayB}=require('./b.js')sayB()函数sayA(){console.log('sayA')}//b.jsmodule.exports={sayB}const{sayA}=require('./a.js')console.log(typeofsayA)sayA()函数sayB(){console.log('sayA')}方案二:间接调用通过引入事件消息传递,多个模块可以间接传递消息,多个模块也可以通过发送消息相互调用。//a.jsrequire('./b.js')constbus=require('./bus.js')bus.on('sayA',sayA)setTimeout(()=>{bus.emit('sayB')},0)functionsayA(){console.log('sayA')}module.exports={sayA}//b.jsconstbus=require('./bus.js')bus.on('sayB',sayB)setTimeout(()=>{bus.emit('sayA')},0)functionsayB(){console.log('sayB')}module.exports={sayB}//总线.jsconstEventEmitter=require('events')classMyEmitterextendsEventEmitter{}module.exports=newMyEmitter()总结了循环依赖的出现,往往是由于代码结构的问题。你应该主动去避免循环依赖的问题,但是当你遇到这种问题又无法避免的时候,你也应该意识到问题是由循环依赖引起的,并想办法解决。最后给出一个有趣的问题,下面的代码运行nodea.js会输出什么?为什么?//a.jsvarmoduleB=require('./b.js')setInterval(()=>{console.log('setIntervalA')},500)setTimeout(()=>{console.log('setTimeoutmoduleA')moduleB.sayB()},2000)functionsayA(){console.log('sayA')}module.exports={sayA}//b.jsvarmoduleA=require('./a.js')setInterval(()=>{console.log('setIntervalB')},500)setTimeout(()=>{console.log('setTimeoutmoduleB')moduleA.sayA()},2000)functionsayB(){console.log('sayB')}module.exports={sayB}