大家好,我用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;之后手动查找实例。注射,但我希望有一些更优雅的解决方案。
答案 0 :(得分:2)
你肯定有一个循环依赖,如果你使用不同的语言,我告诉你使用控制模式的反转,但使用你的问题和容器有点困难。
如果您可以在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
另一方面,这会在每个路由/控制器上创建一个新实例。如果您只需要一个实例。你可以这样做,更容易,也不需要命名空间。
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的容器默认创建单例,你可以急切地创建副本,然后允许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);
}
});