簡體   English   中英

Backbone.js:如何在模型刪除時從事件中取消綁定

[英]Backbone.js: how to unbind from events, on model remove

在骨干網中,我們有一個使用事件聚合器的應用程序,位於window.App.Events現在,在許多視圖中,我們綁定到該聚合器,我手動在視圖上編寫了一個destroy函數,該函數處理來自該事件聚合器的解除綁定然后刪除視圖。 (而不是直接刪除視圖)。

現在,某些模型我們也需要這個功能,但我無法弄清楚如何解決它。

某些模型需要綁定到某些事件,但也許我錯了,但如果我們從集合中刪除一個模型,由於這些綁定到仍然存在的事件聚合器,它會保留在內存中。

模型上沒有真正的刪除功能,就像視圖一樣。 那我怎么解決這個問題呢?

編輯請求,一些代碼示例。

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始終處於適當位置,以便於在整個應用程序中傳遞事件。

代碼示例顯示,即使從集合中刪除它們,它們也不再存在於房屋中,但是當竊賊進入房屋時仍然執行hide命令。

我看到即使綁定事件方向是這樣的方式Object1 - > listen - > Object2它必須被刪除,以便Object1丟失任何活動引用。

並且看到聽模型remove事件不是解決方案,因為它沒有在Collection.reset()調用中調用,那么我們有兩個解決方案:

1.覆蓋正常的Collection cleanUp

正如@dira sais在這里,您可以覆蓋Collection._removeReference以更正確地清除方法。

我不喜歡這個解決方案有兩個原因:

  • 我不喜歡覆蓋一個必須在它之后調用super的方法。
  • 我不喜歡覆蓋私有方法

2.重新包裝Collection.reset()調用

相反的是:不添加更深層的功能 ,而是添加更高的功能

然后,不是直接調用Collection.reset() ,而是可以在靜默刪除之前調用cleanUp模型的實現:

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對象保留。 看起來像程序員透視鏈接事件偵聽的對象 - >到 - >被偵聽的對象但實際上完全相反: 被偵聽的對象 - >到 - >正在偵聽的對象

現在,如果我們使用Collection.reset()清空Collection,我們看到已刪除users鏈接,但AppEvents鏈接仍然存在:

我們的目標保留2

users鏈接已經消失,鏈接OurModel.collection我認為是Collection._removeReference()作業的一部分。

當我們使用我們的Collection.cleanUp()方法時,對象從內存中消失,我無法讓Chrome.profile工具明確告訴我@ 314019對象已被刪除,但我可以看到它已不再是內存對象

我認為干凈的引用過程是Backbone一個棘手的部分。

Collection刪除Model ,集合會注意unbind模型上與其自身綁定的集合的任何事件。 檢查這個私有的Collection方法

也許你可以在你的聚合器中使用這樣的技術:

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

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

在這種情況下,綁定的方向是Aggregator - > Model 如果方向相反我不認為你必須在模型刪除后進行任何清潔。

我沒有像fguillen建議的那樣用cleanUp包裝Collectionreset ,而是直接擴展Collection和覆蓋reset 原因是cleanUp僅在客戶端代碼中生效,但在庫(即Backbone )中則不生效。 例如, Collection.fetch可以在內部調用Collection.reset 除非修改Backbone的源代碼,否則在調用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創建新的集合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM