Backbone.js:如何从事件中取消绑定,删除模型

在主干中,我们有一个应用程序使用事件聚合器,位于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总是在适当的位置,以方便通过整个应用程序传递事件。

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


我发现,即使绑定事件的方向是这样,Object1 - > listen - > Object2,它也必须被移除,以便Object1丢失任何活动引用。

由于在Collection.reset()调用中没有调用模型remove事件,因此听到模型remove事件并不是解决方案,我们有两种解决方案:

1.覆盖正常的Collection CleanUp

作为@dira sais,您可以覆盖Collection._removeReference以更好地清理该方法。

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

  • 我不喜欢覆盖在它之后必须调用super的方法。
  • 我不喜欢重写私有方法
  • 2.重写您的Collection.reset()调用

    正好相反:不是增加更深层次的功能,而是添加上层功能。

    然后,不要直接调用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。

    更新:验证在删除绑定事件链接后删除模型

    首先我们验证在Object2中侦听事件的Object1在方向Obect2 - > Object1中创建链接:

    我们的对象被保留

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

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

    我们的对象被保留2

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

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


    我认为干净的参考过程是Backbone一个棘手部分。

    当您从Collection删除Model ,集合会小心unbind与其自身绑定的集合的模型上的任何事件。 检查这个私人收藏方法。

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

    // ... Aggregator code
    the_model.on( "remove", this.unlinkModel, this );
    // ... more Aggregator code
    
    unlinkModel: function( model ){
      model.off( null, null, this );
    }
    

    这就是绑定的方向是Aggregator - > Model。 如果方向相反,我认为在Model删除后,您不必进行任何清洁。


    相反,包装的CollectionresetcleanUp作为fguillen建议,我宁愿延长Collection并覆盖reset直接。 原因是cleanUp只在客户端代码中生效,而不在库中(即Backbone)。 例如, Collection.fetch可能会在内部调用Collection.reset 。 除非修改骨干的源代码,否则在调用Collection.fetch后,我们不能解除事件中的模型(如在cleanUp )。

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

    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创建新的集合。

    链接地址: http://www.djcxy.com/p/63091.html

    上一篇: Backbone.js: how to unbind from events, on model remove

    下一篇: How can i put a compiled boot sector onto a USB stick or disk?