Ember.js Application.inject循环依赖项

时间:2014-03-29 19:48:33

标签: javascript ember.js dependency-injection frontend single-page-application

大家好,我用ember.js构建我的应用程序大约需要2周时间,现在是时候将我的项目布局整合到最终的形状中了。为此,我开始研究使用Ember的注册/注入机制,而不仅仅是创建全局单例并将它们附加到我的App对象(有关Ember依赖注入的优秀描述,请参阅here)< / p>

我坚持使用标准的依赖注入困境 - 循环引用。

让我们说,我有两个类似经理的课程,我需要在整个申请过程中提供这些课程。我们称之为AuthManager和DataManager。

App.AuthManager = Ember.Object.extend({
    logIn: function (user) {
        var promise = this.dataManager.post("/session/new", user);
        //...
    }
});

App.DataManager = Ember.Object.extend({
    getJSON: function (url) {
        if (!this.authManager.get("isLoggedIn")) {
            return false;
        }
        //...
    }
});

因此,正如您所见,dataManager需要访问authManager,反之亦然。 我对解决方案的天真看法是这样的:

App.initializer({
    name: "dataManager",

    initialize: function (container, application) {
        application.register("my:dataManager", application.DataManager);
        application.inject("my:authManager", "dataManager", "my:dataManager");
    }
});

App.initializer({
    name: "authManager",

    initialize: function (container, application) {
        application.register("my:authManager", application.AuthManager);
        application.inject("my:dataManager", "authManager", "my:authManager");
    }
});

可以预见,这会导致死循环。我希望依赖注入系统可以尝试一些狡猾的玩杂耍,比如节点require那样,但没有。

我试过了:

  • my:authManager注册后,将第一次注入移动到第二个初始化程序。
  • 在前两个
  • 之后将第一次注入移动到自己的初始化程序中
  • 将这些内容的任意组合放入链接文章中的Ember.onLoad('Ember.Application', ...)

不幸的是,我尝试的所有内容都以堆栈溢出结束(双关语意图: - ))。

我错过了什么吗?该领域的文档非常稀少。 当然,我总是可以在官方&#39;之后手动查找实例。注射,但我希望有一些更优雅的解决方案。

1 个答案:

答案 0 :(得分:2)

你肯定有一个循环依赖,如果你使用不同的语言,我告诉你使用控制模式的反转,但使用你的问题和容器有点困难。

解决方案1 ​​

如果您可以在manager之类的名称空间或类似名称下添加它们,那么这就是解决方案(它紧密耦合,但代码已紧密耦合,几乎足够他们可以在一起或混合在另一个上。)

App.Manager = Ember.Object.extend({
  init: function(){
    // late fake injection
    this.authManager.dataManager = this.dataManager;
    this.dataManager.authManager = this.authManager;
  }
});


App.initializer({
    name: "manager",
    after:['dataManager', 'authManager'],

    initialize: function (container, application) {
        application.register("my:manager", application.Manager);
        application.inject("my:manager", "dataManager", "my:dataManager");
        application.inject("my:manager", "authManager", "my:authManager");
        application.inject("controller", "manager", "my:manager");
        application.inject("route", "manager", "my:manager");
    }
});

App.initializer({
    name: "dataManager",

    initialize: function (container, application) {
        application.register("my:dataManager", application.DataManager);
    }
});

App.initializer({
    name: "authManager",

    initialize: function (container, application) {
        application.register("my:authManager", application.AuthManager);
    }
});

一个例子:

http://emberjs.jsbin.com/mopaquko/2/edit

解决方案2

另一方面,这会在每个路由/控制器上创建一个新实例。如果您只需要一个实例。你可以这样做,更容易,也不需要命名空间。

App.initializer({
    name: "joinManagers",
    after:['dataManager', 'authManager'],

    initialize: function (container, application) {
      var dataManager = container.lookup('my:dataManager'),
          authManager = container.lookup('my:authManager');

        authManager.dataManager = dataManager;
        dataManager.authManager = authManager;

        application.register("my:jointDataManager", dataManager, {instantiate:false});
        application.register("my:jointAuthManager", authManager, {instantiate:false});
        application.inject("controller", "dataManager", "my:jointDataManager");
        application.inject("controller", "authManager", "my:jointAuthManager");
        application.inject("route", "dataManager", "my:jointDataManager");
        application.inject("route", "authManager", "my:jointAuthManager");
    }
});


App.initializer({
    name: "dataManager",

    initialize: function (container, application) {
        application.register("my:dataManager", application.DataManager);
    }
});

App.initializer({
    name: "authManager",

    initialize: function (container, application) {
        application.register("my:authManager", application.AuthManager);
    }
});

http://emberjs.jsbin.com/mopaquko/3/edit

解决方案3

正如所指出的那样,Ember的容器默认创建单例,你可以急切地创建副本,然后允许ember仍然根据原始命名空间解析。

App.initializer({
    name: "joinManagers",
    after:['dataManager', 'authManager'],

    initialize: function (container, application) {
      var dataManager = container.lookup('my:dataManager'),
          authManager = container.lookup('my:authManager');

        authManager.dataManager = dataManager;
        dataManager.authManager = authManager;

        application.inject("controller", "dataManager", "my:dataManager");
        application.inject("controller", "authManager", "my:authManager");
        application.inject("route", "dataManager", "my:dataManager");
        application.inject("route", "authManager", "my:authManager");
    }
});


App.initializer({
    name: "dataManager",

    initialize: function (container, application) {
        application.register("my:dataManager", application.DataManager);
    }
});

App.initializer({
    name: "authManager",

    initialize: function (container, application) {
        application.register("my:authManager", application.AuthManager);
    }
});

http://emberjs.jsbin.com/mopaquko/7/edit

相关问题