javascript Backbone.js:如何从事件中解除绑定,在模型上删除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10429648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Backbone.js: how to unbind from events, on model remove
提问by Sander
in backbone we have an app that uses an event Aggregator, located on the window.App.Events
now, in many views, we bind to that aggregator, and i manually wrote a destroy function on a view, which handles unbinding from that event aggregator and then removing the view. (instead of directly removing the view).
在主干中,我们有一个使用事件聚合器的应用程序,位于window.App.Events
现在,在许多视图中,我们绑定到该聚合器,并且我在视图上手动编写了一个销毁函数,该函数处理从该事件聚合器解除绑定,然后删除视图. (而不是直接删除视图)。
now, there were certain models where we needed this functionality as well, but i can't figure out how to tackle it.
现在,在某些模型中我们也需要此功能,但我不知道如何解决它。
certain models need to bind to certain events, but maybe i'm mistaken but if we delete a model from a collection it stays in memory due to these bindings to the event aggregator which are still in place.
某些模型需要绑定到某些事件,但也许我错了,但是如果我们从集合中删除模型,由于这些与事件聚合器的绑定仍然存在,它会保留在内存中。
there isn't really a remove function on a model, like a view has. so how would i tacke this?
模型上并没有真正的删除功能,就像视图一样。那么我将如何解决这个问题?
EDITon request, some code example.
根据要求编辑,一些代码示例。
App = {
Events: _.extend({}, Backbone.Events)
};
var User = Backbone.Model.extend({
initialize: function(){
_.bindAll(this, 'hide');
App.Events.bind('burglar-enters-the-building', this.hide);
},
hide: function(burglarName){
this.set({'isHidden': true});
console.warn("%s is hiding... because %s entered the house", this.get('name'), burglarName);
}
});
var Users = Backbone.Collection.extend({
model: User
});
var House = Backbone.Model.extend({
initialize: function(){
this.set({'inhabitants': new Users()});
},
evacuate: function(){
this.get('inhabitants').reset();
}
});
$(function(){
var myHouse = new House({});
myHouse.get('inhabitants').reset([{id: 1, name: 'John'}, {id: 1, name: 'Jane'}]);
console.log('currently living in the house: ', myHouse.get('inhabitants').toJSON());
App.Events.trigger('burglar-enters-the-building', 'burglar1');
myHouse.evacuate();
console.log('currently living in the house: ', myHouse.get('inhabitants').toJSON());
App.Events.trigger('burglar-enters-the-building', 'burglar2');
});?
view this code in action on jsFiddle (output in the console): http://jsfiddle.net/saelfaer/szvFY/1/
在 jsFiddle 上查看此代码(控制台中的输出):http: //jsfiddle.net/saelfaer/szvFY/1/
as you can see, i don't bind to the events on the model, but to an event aggregator. unbinding events from the model itself, is not necessary because if it's removed nobody will ever trigger an event on it again. but the eventAggregator is always in place, for the ease of passing events through the entire app.
如您所见,我没有绑定到模型上的事件,而是绑定到事件聚合器。从模型本身解除绑定事件是没有必要的,因为如果它被删除,没有人会再次触发它的事件。但 eventAggregator 始终存在,以便于在整个应用程序中传递事件。
the code example shows, that even when they are removed from the collection, they don't live in the house anymore, but still execute the hide command when a burglar enters the house.
代码示例显示,即使将它们从集合中移除,它们也不再住在房子里,但是当窃贼进入房子时仍然执行隐藏命令。
回答by fguillen
I see that even when the binding event direction is this way Object1 -> listening -> Object2it has to be removed in order to Object1lost any alive reference.
我看到即使绑定事件方向是这种方式Object1 -> listen -> Object2它也必须被删除,以便Object1丢失任何活动引用。
And seeing that listening to the Model remove
event is not a solution due it is not called in a Collection.reset()
call then we have two solutions:
看到监听模型remove
事件不是解决方案,因为它没有在Collection.reset()
调用中调用,那么我们有两个解决方案:
1. Overwrite normal Collection cleanUp
1.覆盖正常的Collection清理
As @dira sais hereyou can overwrite Collection._removeReference
to make a more proper cleaning of the method.
正如@dira 所说,您可以覆盖Collection._removeReference
以对方法进行更适当的清理。
I don't like this solutions for two reasons:
我不喜欢这个解决方案有两个原因:
- I don't like to overwrite a method that has to call
super
after it. - I don't like to overwrite private methods
- 我不喜欢覆盖必须
super
在它之后调用的方法。 - 我不喜欢覆盖私有方法
2. Over-wrapping your Collection.reset()
calls
2. 过度包装你的Collection.reset()
电话
Wich is the opposite: instead of adding deeper functionality, add upper functionality.
恰恰相反:不是添加更深层次的功能,而是添加更高级的功能。
Then instead of calling Collection.reset()
directly you can call an implementation that cleanUpthe models before been silently removed:
然后,Collection.reset()
您可以调用一个实现,而不是直接调用,在静默删除之前清理模型:
cleanUp: function( data ){
this.each( function( model ) { model.unlink(); } );
this.reset( data );
}
A sorter version of your code can looks like this:
您的代码的排序器版本可能如下所示:
AppEvents = {};
_.extend(AppEvents, Backbone.Events)
var User = Backbone.Model.extend({
initialize: function(){
AppEvents.on('my_event', this.listen, this);
},
listen: function(){
console.log("%s still listening...", this.get('name'));
},
unlink: function(){
AppEvents.off( null, null, this );
}
});
var Users = Backbone.Collection.extend({
model: User,
cleanUp: function( data ){
this.each( function( model ) { model.unlink(); } );
this.reset( data );
}
});
// testing
var users = new Users([{name: 'John'}]);
console.log('users.size: ', users.size()); // 1
AppEvents.trigger('my_event'); // John still listening...
users.cleanUp();
console.log('users.size: ', users.size()); // 0
AppEvents.trigger('my_event'); // (nothing)
Check the jsFiddle.
检查jsFiddle。
Update: Verification that the Model is removed after remove the binding-event link
更新:在删除绑定事件链接后验证模型是否被删除
First thing we verify that Object1 listening to an event in Object2 creates a link in the direction Obect2 -> Object1:
首先,我们验证 Object1 侦听 Object2 中的事件会创建一个方向为Obect2 -> Object1 的链接:
In the above image we see as the Model (@314019) is not only retained by the users
collection but also for the AppEvents
object which is observing. Looks like the event linkingfor a programmer perspective is Object that listen -> to -> Object that is listenedbut in fact is completely the opposite: Object that is listened -> to -> Object that is listening.
在上图中,我们看到模型 (@314019) 不仅被users
集合保留,而且AppEvents
被观察的对象保留。看起来程序员视角的事件链接是Object that listen -> to -> Object that is listened但实际上完全相反:Object that is listener -> to -> Object that is listen。
Now if we use the Collection.reset()
to empty the Collection we see as the users
link has been removed but the AppEvents
link remains:
现在,如果我们使用Collection.reset()
清空集合,我们会看到users
链接已被删除,但AppEvents
链接仍然存在:
The users
link has disappear and also the link OurModel.collection
what I think is part of the Collection._removeReference()
job.
该users
链接已消失,而且OurModel.collection
我认为该链接也是Collection._removeReference()
工作的一部分。
When we use our Collection.cleanUp()
method the object disappear from the memory, I can't make the Chrome.profile
tool to explicitly telling me the object @314019 has been removedbut I can see that it is not anymore among the memory objects.
当我们使用我们的Collection.cleanUp()
方法时,对象从内存中消失,我无法让Chrome.profile
工具明确告诉我对象@314019 已被删除,但我可以看到它不再存在于内存对象中。
回答by fguillen
I think the clean references process is a tricky part of Backbone
.
我认为干净的引用过程是Backbone
.
When you remove a Model
from a Collection
the Collection takes care to unbind
any event on the Model that the Collection its self is binding. Check this private Collection method.
当您Model
从Collection
Collection 中删除 a 时,Collection 会处理unbind
Model 上与 Collection 自身绑定的任何事件。检查此私有 Collection 方法。
Maybe you can use such a same technique in your Aggregator:
也许您可以在聚合器中使用相同的技术:
// ... Aggregator code
the_model.on( "remove", this.unlinkModel, this );
// ... more Aggregator code
unlinkModel: function( model ){
model.off( null, null, this );
}
This is in the case the direction of the binding is Aggregator -> Model. If the direction is the opposite I don't think you have to make any cleaning after Model removed.
这是在绑定方向为Aggregator -> Model 的情况下。如果方向相反,我认为您在移除模型后不必进行任何清洁。
回答by Hui Zheng
Instead of wrapping Collection
's reset
with cleanUp
as fguillen suggested, I prefer extending Collection
and overriding reset
directly. The reason is that
cleanUp
takes effect only in client's code, but not in library(i.e. Backbone)'s.
For example, Collection.fetch
may internally call Collection.reset
. Unless modifying the Backbone'ssource code, we cannot unbind models from events(as in cleanUp
) after calling Collection.fetch
.
相反,包装的Collection
“Sreset
与cleanUp
作为fguillen建议,我宁愿延伸Collection
并覆盖reset
直接。原因是
cleanUp
它只在客户端的代码中生效,而在库(即Backbone)的代码中无效。例如,Collection.fetch
可以在内部调用Collection.reset
. 除非修改Backbone 的源代码,否则我们无法cleanUp
在调用Collection.fetch
.
Basically, my suggested snippet is as follows:
基本上,我建议的片段如下:
var MyCollection = Backbone.Collection.extend({
reset: function(models, options) {
this.each(function(model) {
model.unlink(); // same as fguillen's code
});
Backbone.Collection.prototype.reset.apply(this, arguments);
}
});
Later, we can create new collections based on MyCollection
.
稍后,我们可以基于MyCollection
.