2013-03-26 45 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