检查Nodejs循环依赖

相信有用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/ 得到如下结果,显示出了对应的循环依赖

关于chenzujie

非著名码农一枚,认真工作,快乐生活
此条目发表在Nodejs分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注