Утечка памяти при фильтрации магистральной коллекции

У меня есть фильтр, работающий над моей базовой коллекцией. Введите поиск в поле поиска и список живых фильтров. Работает отлично, или я так думал. Когда я посмотрел на снимок кучи памяти в Chrome, я увидел утечку памяти при каждом поиске... 6 мегабайт 8 мегабайт... вскоре снимки кучи составляют более 100 мегабайт.

Я изолировал проблему в представлении ниже. Если я закомментирую this.listenTo в функции инициализации, у меня больше не будет утечки памяти.

Итак, мой вопрос заключается в том, как мне сохранить эти прослушиватели событий и живую фильтрацию в коллекции без утечек.

var View = Backbone.View.extend({

    tagName: 'tr',

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

    events: {
        'click .edit': 'edit',
        'click .delete': 'delete',
    },

    edit: function() { /* EDIT */ },

    delete: function() {
        this.model.destroy(); //backbone
    },

    render: function () {
        var template = _.template( ProductTemplate )
        this.$el.html( template({ this.model.toJSON() }) )
        return this;
    }

})


var ListView = Backbone.View.extend({

    initialize: function()
    {
        this.collection = new Collection( Products ) //products are bootstrapped on load
    },

    render: function (terms)
    {
        this.$el.html( ListTemplate );

        var filtered = Shop.products.collection.search(terms)

        _.each(filtered, this.addOne, this)

        //append list to table
        $('#products').html( this.el )

        return this
    },

    addOne: function (product)
    {
        this.$el.find('tbody').append(
            new View({ model: product }).render().el
        )

        return this
    },

});

var Collection = Backbone.Collection.extend({

    model: Model,

    search : function(letters){

        //set up a RegEx pattern
        var pattern = new RegExp(letters,"gi")

        //filter the collection
        return this.filter(function(model)
        {
            if(letters == "") return true //if search string is empty return true
            return pattern.test(model.attributes['Product']['name'])
        });
    }


});

РЕШЕНО:

Это мой новый метод поиска. Я больше не фильтрую коллекцию и не перерисовываю. Я просто перебираю коллекцию, и если модель соответствует поиску, мы запускаем событие «показать», если ее нет в поиске, мы запускаем событие «скрыть». Затем мы подписываемся на эти события в представлении и действуем соответственно.

функция поиска из коллекции: search : function(query){

    //set up a RegEx pattern
    var pattern = new RegExp(query,"gi")

    //filter the collection
    this.each(function(model){
      if ( pattern.test(model.attributes['Product']['name']) ){
        model.trigger('show')
      }
      else{
        model.trigger('hide')
      }
});
}

Новое представление: var ProductView = Backbone.View.extend({

    tagName: 'tr',

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

    hide: function()
    {
      this.$el.addClass('hide')
    },

    show: function()
    {
      this.$el.removeClass('hide')
    },

    render: function ()
    {
        var template = _.template( ProductTemplate )
        this.$el.html( template( {data: this.model.toJSON(), Utils: Shop.utils} ) )
        return this;
    }

});

person Neil Holcomb    schedule 20.01.2013    source источник
comment
Итак, вы создаете много экземпляров View, но никогда не вызываете для них remove?   -  person mu is too short    schedule 20.01.2013
comment
поэтому я знаю, что моя проблема в том, что я создаю бесконечные представления и никогда их не закрываю. Я просто пытаюсь придумать хороший метод для отслеживания просмотров, чтобы я мог их закрыть. Или, как предложил @anshr ниже, просто скрыть/показать их на основе запроса. Такой метод ускользал от меня до сих пор.   -  person Neil Holcomb    schedule 20.01.2013


Ответы (1)


Чтобы расширить то, что @mu уже прокомментировал, вы не удаляете представления, которые вы создали. Их нет в DOM, но они все еще висят в памяти, потому что имеют ссылку на ваши модели (поэтому сборщик мусора не удалит их за вас).

У вас есть несколько вариантов:

  1. Отслеживайте все представления, которые создаются addOne, и удаляйте их каждый раз, когда вызывается render.
  2. Сделайте так, чтобы ваш код отображал/скрывал представления, а не создавал/уничтожал каждый раз при изменении критериев фильтра. Это больше работы, но это, безусловно, более оптимальное решение.
person anushr    schedule 20.01.2013
comment
Спасибо. Я обновил свой вопрос решением, основанным на вашем ответе выше. - person Neil Holcomb; 20.01.2013