使用requireJs的模块中的循环依赖关系

时间:2012-06-29 15:41:21

标签: javascript requirejs dependency-management circular-dependency

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

我尝试使用此代码,但似乎无效。怎么了?

P.S .:
阅读评论以查看输出,
特别是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 () {
    });
}());

3 个答案:

答案 0 :(得分: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');
    }
    ...
});

答案 1 :(得分:0)

我经常遇到使用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()
});

答案 2 :(得分:0)

一个选项不是返回模块本身,而是一个实例化模块的函数(在这个例子中,它将是一个构造函数,如在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;
    }
    
  • 文件ClassA.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');
        }
    }
    
  • 文件ClassB.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();
    
    });
    

最后,输出将是:

我是ClassB

我是ClassB

我是ClassA

我是ClassA