嗨,我使用 ember.js 构建应用程序大约需要 2 周时间,现在是时候将我的项目布局整理成最终形状了。为此,我开始考虑使用 Ember 的注册/注入(inject)机制,而不仅仅是创建全局单例并将它们附加到我的 App 对象(有关 Ember 中依赖注入(inject)的精彩描述,请参阅 here )
我陷入了标准依赖注入(inject)困境 - 循环引用。
比方说,我有两个类似管理器的类,我需要在整个应用程序中使用它们。我们将它们称为 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");
}
});
不出所料,这会导致死循环。我希望依赖注入(inject)系统会尝试一些巧妙的技巧,就像节点的 require
所做的那样,但没有。
我已经尝试过:
- 注册
my:authManager
后,将第一个注入(inject)移至第二个初始值设定项。 - 将第一个注入(inject)移到其自己的初始化程序中,位于前两个注入(inject)之后
- 将这些内容的任意组合放入链接文章中的
Ember.onLoad('Ember.Application', ...)
不幸的是,我尝试的一切都以堆栈溢出结束(双关语:-))。
我错过了什么吗?该领域的文档非常稀疏。 当然,我总是可以在“官方”注入(inject)后手动查找实例,但我希望有一些更优雅的解决方案。
最佳答案
你肯定有循环依赖,如果你使用不同的语言,我会告诉你使用控制反转模式,但是使用你的问题和容器有点困难。
解决方案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
另一方面,这会在每个路由/ Controller 上创建一个新实例。如果您只需要一个实例。您可以这样做,更容易,并且不需要命名空间。
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);
}
});
关于javascript - Ember.js Application.inject 循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22736022/