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

Circular Dependencies in modules using requireJs

本文关键字:依赖 关系 循环 模块 requireJs 使用      更新时间:2023-09-26

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

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

附言:
阅读注释以查看输出,
尤其是 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 () {
    });
}());

您应该能够在 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');
    }
    ...
});

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

一种选择是不返回模块本身,而是返回实例化模块的函数(在本例中,它将是打字稿中定义的构造函数,底部是生成的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');
        }
    }
    
  • File 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代码:

  • 文件类 A.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;
    });
    
  • 文件类 B.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;
    });
    
  • 文件主测试.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类

我是A类

我是A类