【问题标题】:Circular Dependencies in modules using requireJs使用 requireJs 的模块中的循环依赖
【发布时间】:2012-07-01 03:57:06
【问题描述】:

阅读 requireJs 文档,
为了修复循环依赖,建议使用exports 为模块创建一个空对象,该对象可立即供其他模块引用。

我尝试了这段代码,但它似乎不起作用。怎么了?

附:
阅读 cmets 以查看输出,
尤其是 setTimeout 调用中的 B 模块。


// A module
define([
    'b'
], function (b) {
    console.log('B:', b); // B, Object
    var A = {
        boo: 1
    };

    return A;
});

// B module
define([
    'a',
    'exports'
], function (a, exports) {
    console.log('A:', a); // A, undefined (as I was expecting)
    exports.A = function () {
        return a;
    }

    var B = {
        bar: 1
    };

    setTimeout(function () {
        console.log('exports.A', exports.A()); // exports.A undefined 
                                           // I would like to access the A object
                                           // which is defined in A module
    }, 500);

    return B;
});

// main.js

(function () {

    define([
        'a'
    ], function () {
    });
}());

【问题讨论】:

标签: javascript requirejs dependency-management circular-dependency


【解决方案1】:

您应该可以在 B 模块中使用同步版本的require() 来访问“A”模块:

// B module
define([
    'a',
    'exports'
], function (a, exports) {
    console.log('A:', a); // A, undefined (as I was expecting)
    exports.A = function () {
        return require('a');
    }
    ...
});

【讨论】:

    【解决方案2】:

    我经常遇到循环问题,使用 AMD 模块构建一个应用程序核心,它既支持许多模块,又包含配置或其他有用的对象供这些模块使用。

    我今天做了一些实验,这似乎工作得很好。

    define(['exports', 'underscore', './config', './mediator'],
      function (exports, _, Backbone, config, Mediator){
    
        Core = /* ... */
    
        // Publicize a core 'singleton' so that it's dependencies can access it, and so can modules that define it as a dependency themselves.
        core = new Core()
        exports.core = core //publicize it in a way that supports circularity
        return core // And also publicize it normally
      }
    )
    

    这两个对象都是“===”,所以这看起来很有希望。

    编辑:

    上述方法在优化后不起作用。这是另一种可能(未经测试)的方法: https://github.com/requirejs/example-multipage/blob/master/www/js/app/main1.js#L2

    define(function (require) {
      var $ = require('jquery'),
          lib = require('./lib'),
          Core;
    
       Core = /* ... */
    
       return new Core()
    });
    

    【讨论】:

    • 其实我不会用这个方法。它适用于未优化的代码,但如果您在其上运行优化器,您的导出将不可用,看起来像。
    • 我自己现在正在努力解决循环依赖的问题,所以想知道您是否有建议的替代方案
    • 很遗憾没有。一年来一直是个问题,所以我一直在使用 RequireJS 和 CurlJS 来管理应用程序模块。我的“解决方案”是将中介对象的引用传递给中介所依赖的所有内容,并在“页面”级别启动新的依赖链。这看起来像这样:github.com/SimpleAsCouldBe/appCore/blob/master/shared/appCore/… 虽然不是很好。我希望能够始终通过声明获得我的依赖项:(
    • 我会看看谢谢。今天早上等着下班,我在博客上写了我认为 require.js 有问题的所有内容——如果不是在已经在使用它的商店签订合同,我永远不会自愿这样做:codrspace.com/dexygen/…跨度>
    • 我真的很喜欢 AMD 模块。它们比我发现的任何替代品都要好得多。我当前的项目使用 requireJS 管理 135 个 .coffee 模块和 72 个 .hbs 模板。循环问题是真实存在的,并且确实会影响组织,但您的帖子提到的 DRY 问题似乎很小,并且是一种特性——能够控制重命名文件名和变量名之间的依赖关系很好。
    【解决方案3】:

    一种选择是不返回模块本身,而是实例化模块的函数(在本例中,它将是 typescript 中定义的构造函数,底部是生成的 js 代码 -注意接口不生成.js代码)

    • 文件 IA.ts

      /// <reference path="IB.ts" />
      interface IA{
          funcA();
          _classB : IB;
      }
      
    • 文件 IB.ts

      /// <reference path="IA.ts" />
      interface IB{
          funcB();
          _classA : IA;
      }
      
    • 文件类A.ts

      /// <reference path="IA.ts" />
      /// <reference path="IB.ts" />
      
      export class ClassA implements IA
      {
          _classB : IB = null;
      
          constructor(classB : IB)
          {
              this._classB = classB;
              if (classB){
                  this._classB._classA = this;
              }
              return this;
          }
      
          funcA(){
              console.log('I am ClassA');
          }
      }
      
    • 文件类B.ts

      /// <reference path="IA.ts" />
      /// <reference path="IB.ts" />
      export class ClassB implements IB
      {
          _classA : IA = null;
          constructor(classA : IA)
          {
              this._classA = classA;
              if (classA){
                  this._classA._classB = this;
              }
              return this;
          }
          funcB(){
              console.log('I am ClassB');
          }
      }
      
    • 文件 MainTest.ts

      /// <reference path="../../def/require.d.ts" />
      /// <reference path="IA.ts" />
      /// <reference path="IB.ts" />
      define(['ClassA', 'ClassB'],
          function (classA, classB)
          {
              var aa : IA = new classA.ClassA();
              var bb : IB = new classB.ClassB(aa);
      
              bb.funcB();
              aa._classB.funcB();
              bb._classA.funcA();
              aa.funcA();
          });
      

    以及生成的js代码:

    • 文件 ClassA.js

      define(["require", "exports"], function(require, exports) {
          var ClassA = (function () {
              function ClassA(classB) {
                  this._classB = null;
                  this._classB = classB;
                  if (classB) {
                      this._classB._classA = this;
                  }
                  return this;
              }
              ClassA.prototype.funcA = function () {
                  console.log('I am ClassA');
              };
              return ClassA;
          })();
          exports.ClassA = ClassA;
      });
      
    • 文件 ClassB.js

      define(["require", "exports"], function(require, exports) {
          var ClassB = (function () {
              function ClassB(classA) {
                  this._classA = null;
                  this._classA = classA;
                  if (classA) {
                      this._classA._classB = this;
                  }
                  return this;
              }
              ClassB.prototype.funcB = function () {
                  console.log('I am ClassB');
              };
              return ClassB;
          })();
          exports.ClassB = ClassB;
      });
      
    • 文件 MainTest.js

      define(['ClassA', 'ClassB'], function (classA, classB) {
      
          var aa = new classA.ClassA();
          var bb = new classB.ClassB(aa);
      
          bb.funcB();
          aa._classB.funcB();
          bb._classA.funcA();
          aa.funcA();
      
      });
      

    最后,输出将是:

    我是B班

    我是B班

    我是甲级

    我是甲级

    【讨论】:

      猜你喜欢
      • 2017-10-27
      • 1970-01-01
      • 1970-01-01
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 2014-09-22
      • 2018-03-17
      相关资源
      最近更新 更多