内存使用骨干从DOM中删除项目时泄漏

时间:2013-03-26 13:33:45

标签: backbone.js backbone-layout-manager

删除后,我遇到了DOM元素留在内存中的问题。我已经设置了如下所示的示例。注意我使用主干布局管理器插件来管理我的视图(以及jQuery)。

我在删除列表中的一个项目之前和之后在Chrome中完成了堆快照,并将两者进行了比较:

Chrome heap snapshot comparison

正如您所见,LI元素仍在内存中。

Backbone Layout Manager在删除视图时会调用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>

1 个答案:

答案 0 :(得分: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()的{​​{3}}将移除this.$el并停止收听模型:

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

编辑:感谢您在线发布代码。这就是我认为正在发生的事情(我也在记录未来的观众)。

如果你拍摄快照,过滤分离的DOM树,你会看到:

Web Inspector Snapshot

重要的部分是保留树:阻止LI被删除的引用。唯一重要的是sizzle-1364380997635。它不是来自你的代码,它实际上来自jQuery,更具体地来自它的Sizzle引擎。关键来自这里:

default implementation

如果你进一步查看代码,你会看到有一个缓存:

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

因此,简而言之,您的代码不会泄漏,但jQuery有一个内部缓存,无论如何都无法将其删除。此缓存只能包含几十个元素,因此它不会永久保留元素。