循环依赖问题简单示例
从a.js启动,引用B,去到b.js执行,在b.js里引用A时且使用doA时会出现问题。解释:这是因为依赖循环,A启动时引用B,而B又引用A,此时A仍没运行完export出来,暂时为空对象。
//a.js
let B = require('./b.js')
console.log('a.js begin')
B.doB()
function doA () {
console.log('doA')
}
module.exports = {
doA: doA
}
let A = require('./a.js')
console.log('b.js begin')
A.doA() // TypeError: A.doA is not a function
function doB () {
console.log('doB')
}
module.exports = {
doB: doB
}
解决办法1 先export出来
让a.js先export 出A,就能正常运行,代码修改如下:
module.exports = {
doA: doA
}
let B = require('./b.js')
console.log('a.js begin')
B.doB()
function doA () {
console.log('doA')
}
当然,如果脚本从b.js启动,仍然会抛错的,解决方法同上。
解决办法2 重新设计结构 避开依赖循环
在实际编程时,写着写着出现了a.js <–>b.js这种相互引用的情况这时就要考虑引入c.js,重写代码,让c.js来调用两者干活。避开依赖循环是最好的方式。
c.js<–a.js
c.js<–b.js
另一案例
c.js引用a.js,b.js,a.js引用b.js,b.js引用a.js(即a,b之间依赖循环)
//c.js
let A = require('./a.js')
let B = require('./b.js')
console.log('c.js begin')
A.doA()
B.doB()
//a.js
let B = require('./b.js')
console.log('a.js begin')
function doA () {
console.log('doA')
console.log('B:',B)
}
module.exports = {
doA: doA
}
//b.js
let A = require('./a.js')
console.log('b.js begin')
function doB () {
console.log('doB')
console.log('A:',A) //A:{ }
}
module.exports = {
doB: doB
}
//node c.js 运行结果:
b.js begin
a.js begin
c.js begin
doA
B: { doB: [Function: doB] }
doB
A: {}
可以发现,A在b.js因依赖循环仍为空对象,除了方法一将export置前外,还有另一方法,在方法里require即可,代码修改如下:
//b.js
console.log('b.js begin')
function doB () {
let A = require('./a.js') //require here
console.log('doB')
console.log('A:',A) //A:{ }
}
module.exports = {
doB: doB
}
备注
1.相对于动态引用require,ES6的import能解决问题这种问题。
2.对于依赖循环,isaacs的解决方案解答,原文如下:
a) Don’t have circular deps if possible. (It’s not always possible,
Irealize.)b) Set your module.exports early in your module, before.c)
Take advantage of named Function hoisting, so you can do
module.exports = Foo; var bar = require(‘bar’); function Foo() { … }
That way, even if the Foo function isn’t set up yet, it’ll still refer
to the same thing.