资讯专栏INFORMATION COLUMN

Node.js 如何找出循环依赖的文件?如何解决循环依赖问题?

Panda / 1233人阅读

摘要:本文重点是讲解如何解决循环依赖这个问题。如何找到循环依赖的的文件上文的示例代码很简单,个文件,很容易找出循环依赖。如果有十几个文件,手工去找循环依赖的文件,也是非常麻烦的。

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

如何重现这个问题

</>复制代码

  1. // a.js
  2. const {sayB} = require("./b.js")
  3. sayB()
  4. function sayA () {
  5. console.log("say A")
  6. }
  7. module.exports = {
  8. sayA
  9. }

</>复制代码

  1. // b.js
  2. const {sayA} = require("./a.js")
  3. sayA()
  4. function sayB () {
  5. console.log("say B")
  6. }
  7. module.exports = {
  8. sayB
  9. }

执行下面的代码

</>复制代码

  1. test git:(master)node a.js
  2. /Users/dd/wj-gitlab/tools/test/b.js:3
  3. sayA()
  4. ^
  5. TypeError: sayA is not a function
  6. at Object. (/Users/dd/wj-gitlab/tools/test/b.js:3:1)
  7. at Module._compile (module.js:635:30)
  8. at Object.Module._extensions..js (module.js:646:10)
  9. at Module.load (module.js:554:32)
  10. at tryModuleLoad (module.js:497:12)
  11. at Function.Module._load (module.js:489:3)
  12. at Module.require (module.js:579:17)
  13. at require (internal/module.js:11:18)
  14. at Object. (/Users/dd/wj-gitlab/tools/test/a.js:1:78)
  15. 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放到文件头部,先将自身模块导出,然后再导入其他模块。

来自:http://maples7.com/2016/08/17...

</>复制代码

  1. // a.js
  2. module.exports = {
  3. sayA
  4. }
  5. const {sayB} = require("./b.js")
  6. sayB()
  7. function sayA () {
  8. console.log("say A")
  9. }

</>复制代码

  1. // b.js
  2. module.exports = {
  3. sayB
  4. }
  5. const {sayA} = require("./a.js")
  6. console.log(typeof sayA)
  7. sayA()
  8. function sayB () {
  9. console.log("say A")
  10. }
方案2: 间接调用

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

</>复制代码

  1. // a.js
  2. require("./b.js")
  3. const bus = require("./bus.js")
  4. bus.on("sayA", sayA)
  5. setTimeout(() => {
  6. bus.emit("sayB")
  7. }, 0)
  8. function sayA () {
  9. console.log("say A")
  10. }
  11. module.exports = {
  12. sayA
  13. }

</>复制代码

  1. // b.js
  2. const bus = require("./bus.js")
  3. bus.on("sayB", sayB)
  4. setTimeout(() => {
  5. bus.emit("sayA")
  6. }, 0)
  7. function sayB () {
  8. console.log("say B")
  9. }
  10. module.exports = {
  11. sayB
  12. }

</>复制代码

  1. // bus.js
  2. const EventEmitter = require("events")
  3. class MyEmitter extends EventEmitter {}
  4. module.exports = new MyEmitter()
总结

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

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

</>复制代码

  1. // a.js
  2. var moduleB = require("./b.js")
  3. setInterval(() => {
  4. console.log("setInterval A")
  5. }, 500)
  6. setTimeout(() => {
  7. console.log("setTimeout moduleA")
  8. moduleB.sayB()
  9. }, 2000)
  10. function sayA () {
  11. console.log("say A")
  12. }
  13. module.exports = {
  14. sayA
  15. }

</>复制代码

  1. // b.js
  2. var moduleA = require("./a.js")
  3. setInterval(() => {
  4. console.log("setInterval B")
  5. }, 500)
  6. setTimeout(() => {
  7. console.log("setTimeout moduleB")
  8. moduleA.sayA()
  9. }, 2000)
  10. function sayB () {
  11. console.log("say B")
  12. }
  13. module.exports = {
  14. sayB
  15. }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98719.html

相关文章

  • 新鲜出炉8月前端面试题

    摘要:前言最近参加了几场面试,积累了一些高频面试题,我把面试题分为两类,一种是基础试题主要考察前端技基础是否扎实,是否能够将前端知识体系串联。 前言 最近参加了几场面试,积累了一些高频面试题,我把面试题分为两类,一种是基础试题: 主要考察前端技基础是否扎实,是否能够将前端知识体系串联。一种是开放式问题: 考察业务积累,是否有自己的思考,思考问题的方式,这类问题没有标准答案。 基础题 题目的答...

    qingshanli1988 评论0 收藏0
  • Node.js设计模式》Node.js基本模式

    摘要:回调函数是在异步操作完成后传播其操作结果的函数,总是用来替代同步操作的返回指令。下面的图片显示了中事件循环过程当异步操作完成时,执行权就会交给这个异步操作开始的地方,即回调函数。 本系列文章为《Node.js Design Patterns Second Edition》的原文翻译和读书笔记,在GitHub连载更新,同步翻译版链接。 欢迎关注我的专栏,之后的博文将在专栏同步: Enc...

    Seay 评论0 收藏0
  • [译]你并不知道Node

    摘要:问题什么是调用栈并且它是的一部分么调用栈当然是的一部分。为什么理解是重要的因为你在每个进程中只能获取一个调用栈。它是一个从事件队列中跳去事件的循环并且将它们的回调压入到调用栈中。当调用栈为空的时候,事件循环可以决定下一步执行哪一个。 你并不知道Node 原文:You don’t know Node 译者:neal1991 welcome to star my articles-tra...

    miqt 评论0 收藏0
  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    oujie 评论0 收藏0
  • 深入浅出Node.js

    摘要:深入浅出一直想致力于写一篇关于广义讲解系统的文章,苦于时间有限,资源有限。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 深入浅出Node.js 一直想致力于写一篇关于广义讲解Node.js系统的文章,苦于时间有限,资源有限。这篇文章是在结合自己的学习心得以及与行业大佬共同探讨下争对于熟练掌握JS语言后的广义Node.js.至于为什么...

    MadPecker 评论0 收藏0

发表评论

0条评论

Panda

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<