Ember.js Application.inject循环依赖 [英] Ember.js Application.inject circular dependencies

查看:72
本文介绍了Ember.js Application.inject循环依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用ember.js构建应用程序大约需要2周的时间,现在该将我的项目布局整理成最终形状了。为此,我开始研究使用Ember的register / inject机制,而不仅仅是创建全局单例并将它们附加到我的App对象(有关Ember中依赖项注入的详细说明,请参见此处

Hi, I'm about 2 weeks into building my application with ember.js, and the time has come to pull together my project layout into its final shape. To that end, I started looking into using Ember's register / inject mechanism instead of just creating global singletons and attaching them to my App object (for an excellent description of dependency injection in Ember, see here)

我陷入了标准依赖项注入难题-循环引用。

I'm stuck with standard dependency injection dilemma - circular references.

比方说,我在整个应用程序中需要两个类似经理的类。我们称它们为AuthManager和DataManager。

Let's say, I have two manager-like classes that I need available throughout application. Let's call them AuthManager and 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,反之亦然。
我对解决方案的幼稚尝试是这样的:

So, as you see dataManager needs access to authManager and vice-versa. My naive take at a solution was something like this:

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");
    }
});

可以预料,这将导致死循环。我希望依赖项注入系统会尝试一些巧妙的方法,例如node的 require 会这样做,但是没有。

Predictably, this results in a dead loop. I was hoping dependency injection system would try some crafty juggle, like node's require does, but no.

尝试过:


  • my:authManager 之后将第一个注入项移入第二个初始化器中

  • 在前两个注入之后将第一个注入移动到其自己的初始化器中

  • 将它们的任意组合放入 Ember.onLoad('Ember.Application',...)来自链接的文章

  • Moving the first inject into the second initializer, after my:authManager is registered.
  • Moving the first inject into its own initializer, after the first two
  • Putting any combination of these into the Ember.onLoad('Ember.Application', ...) from the linked article

不幸的是,我尝试过的所有操作都以堆栈溢出(双关语:-)结尾。

Unfortunately, everything I tried ended in stack overflow (pun intended :-)).

我错过了什么吗?在这方面的文档很少。
当然,在官方注入之后,我总是可以手动查找实例,但是我希望有一些更优雅的解决方案。

Am I missing something? The documentation is pretty sparse in this area. Of course, I can always manually lookup instance after the 'official' injection, but I was hoping for some more elegant solution.

推荐答案

您肯定有一个循环依赖项,如果您使用其他语言,我会告诉您使用控制模式的反转,但是使用您的问题和容器会有些困难。

You definitely have a circular dependency, and if you were using a different language I'd tell you to use the inversion of control pattern, but it's a little difficult using your problem and the container.

如果可以将它们添加到诸如 manager 之类的命名空间下,这是一个解决方案(它紧密耦合,但是代码已经紧密耦合,几乎可以将它们组合在一起或彼此混合)。

If you're fine adding them under a namespace such as manager or something like that then here's a solution (it's tightly coupled, but the code is tightly coupled already, almost enough that they could be together or a mixin on the other).

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

另一方面,这会在每个路由/控制器上创建一个新实例。如果只需要一个实例。您可以这样操作,轻松得多,并且不需要名称空间。

On another note, this creates a new instance on each route/controller. If you only need one instance. You can do it like so, much easier and doesn't need the namespace.

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

,默认情况下是Ember容器创建的单例,您可以急切创建副本,然后让余烬仍然根据原始名称空间进行解析。

As was pointed out, Ember's container create's singletons by default, you can eagerly create the copies then allow ember to still resolve based on the original namespace.

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

这篇关于Ember.js Application.inject循环依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆