相信有用nodejs开发过项目的开发或多或少会遇到过循环依赖的问题,比如类似如下的错误
nodejs.TypeError: ClassA is not a constructor
at ClassB.bFunction (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/ClassB.js:5:20)
at ClassA.aFunction (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/ClassA.js:6:12)
at ClassController.circularApi (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/classController.js:10:14)
或者
ClassA.aFunction is not a function
at ClassB.bFunction (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/ClassB.js:6:12)
at Function.aFunction (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/ClassA.js:6:12)
at ClassController.circularApi (/Users/chenzujie/work/autoui-bsl/app/controller/testCircular/classController.js:10:14)
类似如上两种要么类找不到,要么类里面的方法找不到,但是类也require了,对应的方法或者变量也存在,但一运行就是提示找不到,那么恭喜你了,一定是遇到依赖循环的问题。
循环依赖是什么
简单说就是A文件里面引用了B文件,B文件里面引用了A文件,很多从前端js开发转nodejs开发的同学第一次写nodejs经常遇到这个问题,比如上面的错误,我们把代码贴出来看就明白了
// ClassA.js
const ClassB = require('./ClassB');
class ClassA {
static aFunction() {
const classB = new ClassB();
classB.bFunction();
}
}
module.exports = ClassA;
//ClassB.js
const ClassA = require('./ClassA');
class ClassB {
bFunction() {
// const classA = new ClassA();
ClassA.aFunction();
}
}
module.exports = ClassB;
为什么会有循环依赖
原因就在于nodejs的加载缓存机制
1、当读取ClassA文件的时候,会把ClassA加入缓存再进行加载操作
2、当读取ClassB文件的时候会,ClassB文件引用了ClassA,由于步骤1,会从缓存中获取ClassA
3、但此时ClassA并没有加载完,因此获取到的ClassA是不完整的,就会报错方法找不到,类找不到
Nodejs的此套加载机制解决了递归依赖的问题,但却没有解决因此带来的空依赖问题,可以说不够完美。
如何查找循环依赖
1、安装madge
npm -g install madge
2、安装graphivz,这个是一个用于输出可视化循环依赖的工具,如下是mac按照方式
brew install graphviz
如果碰到没有brew工具的可以选择如下命令镜像安装
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
madge --circular --image XXX.png path
XXX.svg 是输入的图片名称, path可以是一个目录也可以是一个文件,
比如上面的报错我们输入
madge –circular –image graph.png ./app/controller/testCircular/ 得到如下结果,显示出了对应的循环依赖