【问题标题】:CommonJS / RequireJS - Circular module dependenciesCommonJS / RequireJS - 循环模块依赖
【发布时间】:2017-10-27 07:56:12
【问题描述】:

想问一下commonjs/requirejs循环模块依赖解析背后的机制是什么。

让我举个例子。假设我们有以下模块结构

 modulea
     index.js
     submodulea_a.js
     submodulea_b.js

moduleb
     index.js
     submoduleb_a.js
     submoduleb_b.js

其中 modulea/index.js 和 moduleb/index.js 只是重新导出子模块的有趣功能。即:

 var aa_class = require("./submodulea_a").aaclass;
 var ab_class = require("./submodulea_b").abclass;

 module.exports aa_class;
 module.exports ab_class;

另外,让我们假设在一个子模块中我会这样做:

 var ba_class = require("moduleb").ba_class;

同样适用于 B,但可以说在子模块 b 中我会这样做:

var aa_class = require("modulea").aa_class;

如您所见,一个类在模块之间没有直接循环依赖另一个类,但存在循环模块依赖,因为 modulea 需要 moduleb 并且 moduleb 需要 modulea(更好的说法是从子模块重新导出某些内容)。

节点 commonjs 或 requirejs 如何解决这个问题以避免堆栈溢出?有没有像“后期绑定”之类的东西?我会说不,因为据我所知 commonjs 是同步的。

谢谢

编辑:

所以我对描述的模块结构进行了一些研究,它似乎与以下过程类似:

  1. 解析模块名称(package.json、node_modules、相对路径...)
  2. 加载模块代码(.js文件)
  3. 标记正在初始化(已解决)的当前模块
  4. 准备“空”( {} ) 导出并将其发布到当前模块(其他模块将在 require 期间将其用于导入,即使它是空的)
  5. 处理加载的模块(执行它),如果找到require,则以与当前模块相同的方式解析该模块
  6. 模块执行完成后,将其标记为已初始化(已解决)

如果正在初始化或已经初始化的模块需要再次加载,则使用其导出的缓存版本。

无法解决的问题:

当循环模块即将被加载时,似乎没有办法解决:

var aa_class = require("modulea").aa_class;

在模块 B 内部作为模块 A 的 aa_class 在需要时不可用,因为模块 A 的初始化在从模块 A 导出 aa_class 之前将执行移交给模块 B。所以只有一件事模块 B 可用的是模块 A 中的空导出对象。我看不出有什么方法可以解决这个问题,因为如果我想扩展 bb_module 中的 aa_class,我会迷路。

【问题讨论】:

    标签: requirejs circular-dependency commonjs


    【解决方案1】:

    是否有“后期绑定”之类的东西?

    使用 RequireJS 是的。你可以称之为“后期绑定”或“延迟加载”。

    Circular Dependencies 上的文档使用此示例。

    //Inside b.js:
    define(["require", "a"],
        function(require, a) {
            //"a" in this case will be null if "a" also asked for "b",
            //a circular dependency.
            return function(title) {
                return require("a").doSomething();
            }
        }
    );
    

    【讨论】:

    • 感谢您的回复。但是我没有很好地理解文档。我自己做了一些测试,因为我懒得分析源。查看我的编辑。
    【解决方案2】:

    只要模块不在文件的顶层使用,您可以在导出当前模块后导入它们:

    a.js:

    class A {
      getB() { return new B() }
    }
    
    module.exports = A
    const B = require('./b.js')
    

    b.js:

    class B {
      getA() { return new A() }
    }
    
    module.exports = B
    const A = require('./a.js')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-28
      • 2012-07-01
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 2021-09-18
      • 2014-04-15
      相关资源
      最近更新 更多