Backbone.js:如何从事件中解除绑定,模型移除

在主干中,我们有一个使用事件聚合器的应用程序,位于 window.App.Events现在,在许多视图中,我们绑定到该聚合器,并且我在视图上手动编写了一个销毁函数,该函数处理与该事件聚合器的解除绑定,然后删除该视图.(而不是直接删除视图).

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).

现在,有些模型我们也需要此功能,但我不知道如何解决.

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?

编辑根据要求,一些代码示例.

EDIT on 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');

});​

在 jsFiddle 上查看此代码(在控制台中输出):http://jsfiddle.net/saelfaer/szvFY/1/

view this code in action on jsFiddle (output in the console): http://jsfiddle.net/saelfaer/szvFY/1/

如您所见,我没有绑定到模型上的事件,而是绑定到事件聚合器.从模型本身解除绑定事件是不必要的,因为如果它被删除,没有人会再次触发它的事件.但 eventAggregator 始终存在,以便在整个应用程序中传递事件.

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.

代码示例显示,即使将它们从集合中删除,它们也不再住在房子里,但当窃贼进入房子时仍然执行隐藏命令.

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.

推荐答案

我看到即使绑定事件方向是这样 Object1 -> listener -> Object2 也必须按顺序移除到 Object1 丢失了任何活动引用.

I see that even when the binding event direction is this way Object1 -> listening -> Object2 it has to be removed in order to Object1 lost any alive reference.

并且看到监听模型 remove 事件不是解决方案,因为它没有在 Collection.reset() 调用中被调用,那么我们有两个解决方案:

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:

作为 @dira sais here 您可以覆盖 Collection._removeReference 以对方法进行更适当的清理.

As @dira sais here you can overwrite Collection._removeReference to make a more proper cleaning of the method.

我不喜欢这个解决方案有两个原因:

I don't like this solutions for two reasons:

  • 我不喜欢重写必须在其后调用 super 的方法.
  • 我不喜欢重写私有方法

Wich 正好相反:不是添加更深层次的功能,而是添加高级功能.

Wich is the opposite: instead of adding deeper functionality, add upper functionality.

然后,您可以调用一个实现,而不是直接调用 Collection.reset(),该实现 cleanUp 之前被静默删除的模型:

Then instead of calling Collection.reset() directly you can call an implementation that cleanUp the models before been silently removed:

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)

检查 jsFiddle.

首先我们验证 Object1 监听 Object2 中的事件会创建一个方向为 Obect2 -> Object1 的链接:

First thing we verify that Object1 listening to an event in Object2 creates a link in the direction Obect2 -> Object1:

在上图中,我们看到模型 (@314019) 不仅由 users 集合保留,而且还为正在观察的 AppEvents 对象保留.从程序员的角度来看,事件链接看起来是监听的对象 -> 监听的对象 -> 监听的对象,但实际上完全相反:对象是听 -> 到 -> 正在听的对象.

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 linking for a programmer perspective is Object that listen -> to -> Object that is listened but in fact is completely the opposite: Object that is listened -> to -> Object that is listening.

现在,如果我们使用 Collection.reset() 清空 Collection,我们会看到 users 链接已被删除,但 AppEvents链接仍然存在:

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:

users 链接已经消失,并且链接 OurModel.collection 我认为是 Collection._removeReference() 工作的一部分.

The users link has disappear and also the link OurModel.collection what I think is part of the Collection._removeReference() job.

当我们使用 Collection.cleanUp() 方法时,对象会从内存中消失,我无法让 Chrome.profile 工具明确告诉我 对象@314019 已被删除,但我可以看到它不再在内存对象中.

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 removed but I can see that it is not anymore among the memory objects.

相关文章