2013-03-26 30 views
3

我遇到DOM元素被刪除後留在內存中的問題。我已經建立了一個如下所示的例子。注意我正在使用骨幹佈局管理器插件來管理我的視圖(以及jQuery)。使用主幹從DOM刪除項目時的內存泄漏

我已經做了在Chrome堆快照之前和刪除列表中的項目之一後,並比較了兩種:

Chrome heap snapshot comparison

正如你所看到的LI元素仍然是在內存中。

當刪除視圖時,骨幹佈局管理器會調用view.unbind()和view.stopListening()。

下面是示例代碼。

ListOfViewsToDelete.js

var TestModel = Backbone.Model.extend({ 
    }); 

    var TestCollection = Backbone.Collection.extend({ 
    model: TestModel, 
    }); 

    var ViewToDelete = Backbone.View.extend({ 
    template: "ViewToDelete", 
    tagName: "li", 
    events: { 
     "click .delete-button": "deleteItem" 
    }, 
    deleteItem: function() { 
     this.$el.trigger('remove-item', [this.model.id]); 
    } 
    }); 

    var ListOfViewsToDelete = Backbone.View.extend({ 
    template: "ListOfViewsToDelete", 
    initialize: function() { 
     this.collection = new TestCollection(); 

     for (var i = 0; i < 5; i++) { 
     this.collection.add(new TestModel({id: i})); 
     } 

     this.listenTo(this.collection, 'all', this.render); 
    }, 
    events: { 
     "remove-item": "removeItemFromCollection" 
    }, 
    beforeRender: function() { 

     this.collection.each(function(testModel) { 
     this.insertView("ul", new ViewToDelete({ 
      model: testModel 
     })); 
     }, this); 

    }, 
    removeItemFromCollection: function(event, model) { 
     this.collection.remove(model); 
    } 
    }); 

router.js

app.useLayout("MainLayout").setViews({ 
        "#main": new ListOfViewsToDelete() 
       }).render(); 

ListOfViewsToDelete.html

<ul> 
</ul> 

ViewToDelete.html

View to delete 
<button class="delete-button">x</button> 

回答

4

有幾個問題與您的代碼:

  • 您使用this.$el作爲模型來觸發remove-item事件。您應該改用您的模型。

  • 該視圖應該等待來自模型的事件知道何時移除自身。

這是我想出的代碼。如果它不起作用,請將代碼發佈到某處,以便我可以自己運行它。

 
var ViewToDelete = Backbone.View.extend({ 
    template: "ViewToDelete", 

    tagName: "li", 

    events: { 
     "click .delete-button": "deleteItem" 
    }, 

    initialize: function() { 
     this.listenTo(this.model, 'remove', this.remove); 
    }, 

    deleteItem: function() { 
     this.model.remove(); 
    } 
}); 

的的view.remove()default implementation將刪除this.$el和停止監聽模式:

 
remove: function() { 
    this.$el.remove(); 
    this.stopListening(); 
    return this; 
}, 

編輯:感謝您對網上發佈您的代碼。這是我認爲正在發生的事情(我也爲將來的觀衆記錄)。

如果你把一個快照,過濾器對離DOM樹,你看:

Web Inspector Snapshot

的重要組成部分,是保持樹:即防止LI被刪除引用。唯一重要的是sizzle-1364380997635。它不是來自你的代碼,它實際上來自jQuery,更具體地來自它的Sizzle引擎。關鍵來自這裏:

https://github.com/jquery/sizzle/blob/master/sizzle.js#L33

如果您在代碼中進一步看,你看,有一個緩存:

https://github.com/jquery/sizzle/blob/master/sizzle.js#L1802

因此,概括地說,你的代碼不漏,但jQuery有一個內部緩存,防止它被刪除。此緩存只能包含幾十個元素,因此它不會永久保留元素。

+0

謝謝,我在這裏發佈了一個示例:http://jsfiddle.net/KzVAA/2/當我在刪除項目前後拍攝快照時,我看到HTMLLIElement存儲在內存中。我相信我已經更新了代碼以使用您的建議。 – DownChapel 2013-03-27 09:13:49

+0

謝謝,我會更新我的答案。 – 2013-03-27 10:45:06

+0

太好了,謝謝你的解釋!我會仔細看看嘶嘶聲。 – DownChapel 2013-03-27 12:24:16