本文重点是讲解如何解决循环依赖这个问题。关心这个问题是如何产生的,可以自行谷歌。

如何重现这个问题

// a.js

const {sayB} = require('./b.js')

sayB()

function sayA () {

console.log('say A')

}

module.exports = {

sayA

}

// b.js

const {sayA} = require('./a.js')

sayA()

function sayB () {

console.log('say B')

}

module.exports = {

sayB

}

执行下面的代码

➜ test git:(master) ✗ node a.js

/Users/dd/wj-gitlab/tools/test/b.js:3

sayA()

^

TypeError: sayA is not a function

at Object. (/Users/dd/wj-gitlab/tools/test/b.js:3:1)

at Module._compile (module.js:635:30)

at Object.Module._extensions..js (module.js:646:10)

at Module.load (module.js:554:32)

at tryModuleLoad (module.js:497:12)

at Function.Module._load (module.js:489:3)

at Module.require (module.js:579:17)

at require (internal/module.js:11:18)

at Object. (/Users/dd/wj-gitlab/tools/test/a.js:1:78)

at Module._compile (module.js:635:30)

sayA is not a function那么sayA是个什么呢,实际上它是 undefined

遇到这种问题时,你最好能意识到可能是循环依赖的问题,否则找问题可能事倍功半。

如何找到循环依赖的的文件

上文的示例代码很简单,2个文件,很容易找出循环依赖。如果有十几个文件,手工去找循环依赖的文件,也是非常麻烦的。

下面推荐一个工具 madge, 它可以可视化的查看文件之间的依赖关系。

注意下图1,以cli.js为起点,所有的箭头都是向右展开的,这说明没有循环依赖。如果有箭头出现向左逆流,那么就可能是循环依赖的点。

图2中,出现向左的箭头,说明出现了循环依赖,说明要此处断开循环。

【图1】

【图2】

如何解决循环依赖

方案1: 先导出自身模块

将module.exports放到文件头部,先将自身模块导出,然后再导入其他模块。

// a.js

module.exports = {

sayA

}

const {sayB} = require('./b.js')

sayB()

function sayA () {

console.log('say A')

}

// b.js

module.exports = {

sayB

}

const {sayA} = require('./a.js')

console.log(typeof sayA)

sayA()

function sayB () {

console.log('say A')

}

方案2: 间接调用

通过引入一个event的消息传递,让多个个模块可以间接传递消息,多个模块之间也可以通过发消息相互调用。

// a.js

require('./b.js')

const bus = require('./bus.js')

bus.on('sayA', sayA)

setTimeout(() => {

bus.emit('sayB')

}, 0)

function sayA () {

console.log('say A')

}

module.exports = {

sayA

}

// b.js

const bus = require('./bus.js')

bus.on('sayB', sayB)

setTimeout(() => {

bus.emit('sayA')

}, 0)

function sayB () {

console.log('say B')

}

module.exports = {

sayB

}

// bus.js

const EventEmitter = require('events')

class MyEmitter extends EventEmitter {}

module.exports = new MyEmitter()

总结

出现循环依赖,往往是代码的结构出现了问题。应当主动去避免循环依赖这种问题,但是遇到这种问题,无法避免时,也要意识到是循环依赖导致的问题,并找方案解决。

最后给出一个有意思的问题,下面的代码运行node a.js会输出什么?为什么会这样?

// a.js

var moduleB = require('./b.js')

setInterval(() => {

console.log('setInterval A')

}, 500)

setTimeout(() => {

console.log('setTimeout moduleA')

moduleB.sayB()

}, 2000)

function sayA () {

console.log('say A')

}

module.exports = {

sayA

}

// b.js

var moduleA = require('./a.js')

setInterval(() => {

console.log('setInterval B')

}, 500)

setTimeout(() => {

console.log('setTimeout moduleB')

moduleA.sayA()

}, 2000)

function sayB () {

console.log('say B')

}

module.exports = {

sayB

}

Java头文件找出循环依赖_Node.js 如何找出循环依赖的文件?如何解决循环依赖问题?...相关推荐

  1. html文件显示不了box,Workbox.js registerNavigationRoute找不到/加载html文件

    我几乎完全设置为具有应用程序shell体系结构的pwa,使用像前端(但使用mithril作为渲染引擎)的反应,并使用express node.js后端和ssr,但努力在最后一个问题上过去.Workbo ...

  2. html弹出窗口是浮动,JS实现弹出浮动窗口(支持鼠标拖动和关闭)实例详解

    本文实例讲述了JS实现弹出浮动窗口.分享给大家供大家参考.具体如下: 这里介绍的JS弹出浮动窗口,支持鼠标拖动和关闭,点击链接文字后弹出层窗口,也称作是弹出式对话框吧. 关于一些参数说明: bodyc ...

  3. python递归创建目录_Node.js和Python使用递归查看目录文件和创建目录

    1. 查看目录文件: 1.1 Node实现: let fs = require('fs'); let path = require('path'); let filePath = path.resol ...

  4. node.js 实现udp传输_Node.js实战15:通过udp传输文件。

    本文将要写一个udp服务器,和一个udp客户端,并实现客户端发送文件给服务器. 服务器端 代码如下:var dgram = require("dgram"); server(); ...

  5. bat文件执行多条Linux命令,Js使用WScript.Shell对象执行.bat文件和cmd命令

    WScript.Shell(Windows Script Host Runtime Library)是一个对象,对应的文件是C:/WINDOWS/system32/wshom.ocx,Wscript. ...

  6. 闷棍暴打面试官 Spring源码系列: (一) Spring 如何解决循环依赖

    前言 初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着 "循环依赖,单例模式,Bean的定位加载注 ...

  7. 框架源码专题:Spring是如何解决循环依赖的?

    文章目录 1.什么是循环依赖? 2.解决循环依赖思路 3. 使用了三级缓存还有什么问题?怎么解决的? 4. 手写伪代码解决缓存依赖 5. 二级缓存能否解决循环依赖,三级缓存存在的意义 6. Sprin ...

  8. 万字长文带你吃透Spring是怎样解决循环依赖的

    在Spring框架中,处理循环依赖一直是一个备受关注的话题.这是因为Spring源代码中为了解决循环依赖问题,进行了大量的处理和优化.同时,循环依赖也是Spring高级面试中的必考问题,回答得好可以成 ...

  9. Spring使用三级缓存解决循环依赖?终于完全弄明白了

    文章阅读前推荐 推荐先去看看源码,源码很短,但是对于我们在脑子里构建一个完整思路很重要.看起来非常简单,只需要双击shift,全局查找文件:AbstractAutowireCapableBeanFac ...

最新文章

  1. Namenode主备切换或报 IPC Server handler 23 on 8020
  2. 合并单元格两行_28 HTML5标签学习——table单元格的合并
  3. linux gdb调试问题汇总
  4. 剑指Offer——网易笔试之解救小易
  5. 推荐30个用于微服务的顶级工具
  6. emf java_Java实现emf图片字节流转png(jpg)图片字节流
  7. 把linux插足到域
  8. Engagement Center Communication timer实现逻辑
  9. 进程间通信的方式总结
  10. React中的CSS——styled-components
  11. LDAP命令介绍---dsreplication--initialize
  12. Procrustes Analysis(普氏分析)
  13. VS2008下改变项目的默认属性
  14. Android Studio下载SDK的链接
  15. java svn 创建分支_Eclipse下svn的创建分支/合并/切换使用
  16. 初识ubuntu 安装steam
  17. 万能五笔输入法弹窗_万能五笔输入法广告怎么去掉
  18. rxtx for java_RXTX实现JAVA串口编程
  19. 1044: 不及格率 Python
  20. 怎么验证mysql完整性_MySQL数据库认证高级(一)——数据完整性

热门文章

  1. 阿里正式进军机器人赛道,首款物流机器人“小蛮驴”来了!
  2. “远程办公扼杀了万亿美元的办公经济”
  3. 微软开发趣史 | 我们之所以叫它 RAID 是因为它能干掉 BUG
  4. 如何用 GitHub Actions 写出高质量的 Python代码?
  5. 机器学习项目必经十大磨难,看看自己渡过几劫了?
  6. 2019 十大国产开源项目来势汹汹!
  7. 厉害了!这项技术BAT力捧!程序员:我彻底慌了...
  8. 阿里拟 20 亿美元收购网易考拉;联通 5G 套餐最低 190 元;Rust 1.37.0 发布 | 极客头条...
  9. Java 跌落神坛,Python 继续夺冠....凭啥?
  10. 小米誓要全面接管你的生活!