7

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

现在,在某些模型中我们也需要此功能,但我不知道如何解决它。

某些模型需要绑定到某些事件,但也许我错了,但是如果我们从集合中删除一个模型,由于这些绑定到仍然存在的事件聚合器,它会保留在内存中。

模型上没有真正的删除功能,就像视图一样。那么我将如何解决这个问题?

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

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/

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

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

4

3 回答 3

13

我看到,即使绑定事件方向是Object1 -> Listening -> Object2也必须将其删除,以便Object1丢失任何活动引用。

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

1.覆盖正常的Collection cleanUp

正如@dira sais 在这里,您可以覆盖Collection._removeReference以更适当地清理该方法。

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

  • 我不喜欢覆盖必须super在它之后调用的方法。
  • 我不喜欢覆盖私有方法

2. 过度包装你的Collection.reset()电话

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

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

cleanUp: function( data ){
  this.each( function( model ) { model.unlink(); } );
  this.reset( data );
} 

您的代码的分类器版本可能如下所示:

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的链接:

我们的对象被保留

在上图中,我们看到模型(@314019)不仅被users集合保留,还被AppEvents观察的对象保留。从程序员的角度来看,事件链接似乎是Object that listen -> to -> Object that is listened,但实际上完全相反:Object that is listened -> to -> Object that is listener

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

我们的对象被保留 2

users链接消失了,我认为链接也是工作OurModel.collection的一部分Collection._removeReference()

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

于 2012-05-03T14:01:55.173 回答
1

我认为干净的引用过程是Backbone.

当您ModelCollectionCollection 中删除 a 时,需要注意unbindCollection 自身绑定的 Model 上的任何事件。检查此私有 Collection 方法

也许你可以在你的聚合器中使用同样的技术:

// ... Aggregator code
the_model.on( "remove", this.unlinkModel, this );
// ... more Aggregator code

unlinkModel: function( model ){
  model.off( null, null, this );
}

在这种情况下,绑定的方向是Aggregator -> Model。如果方向相反,我认为您在移除模型后不必进行任何清洁。

于 2012-05-03T10:57:27.407 回答
1

我更喜欢直接扩展和覆盖,而不是像 fguillen 建议的那样包装Collection's 。原因是 它只在客户端代码中生效,而不在库(即Backbone)中生效。例如,可以在内部调用. 除非修改Backbone 的源代码,否则我们不能在调用.resetcleanUpCollectionresetcleanUpCollection.fetchCollection.resetcleanUpCollection.fetch

基本上,我建议的片段如下:

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

稍后,我们可以基于MyCollection.

于 2012-09-07T10:21:07.253 回答