Передача модели Backbone из коллекции в новое представление сохраняет коллекцию в памяти.

У меня есть CompositeView, который показывает список моделей, которые я запросил с сервера, что-то вроде (в CoffeeScript):

class List.Stories extends Marionette.CompositeView
    template: "stories-list-body"
    itemView: List.Story
    itemViewContainer: "#stories-list"

class List.Story extends Marionette.ItemView
    template: "stories-list-story"
    triggers:
        "click .js-show-button": "show:button:clicked"

Представления создаются правильно, передавая коллекцию в качестве аргумента для конструктора, я вижу элементы, и когда я нажимаю кнопку, она вызывает соответствующее событие и обрабатывается. Дело в том, что когда обработчик создает новое представление, показывающее модель, и закрывает старое, ссылка на коллекцию все еще находится в model.collection, занимая часть памяти.

Как правильно удалить эту ссылку? Просто использовать delete model.collection в обработчике перед заменой представления?


person JayC    schedule 05.03.2014    source источник


Ответы (2)


Попробуйте сделать что-то вроде

var model = myCollection.remove(viewModel, { silent: true })

// create new view using `model`

В приведенном выше примере viewModel будет ссылаться на модель представления (так что это будет this.model внутри представления).

Удалив модель из коллекции, она должна быть удалена сборщиком мусора (при условии, что на нее больше нигде не ссылаются...).

person David Sulc    schedule 05.03.2014
comment
Я добавил код в модифицированную версию метода view.close перед вызовом исходного закрытия. Он удаляет все модели из коллекции, оставляя коллекцию без элементов, но коллекция все еще существует. На него не ссылается модель, как раньше, поэтому мне придется посмотреть, где на него есть ссылка (DevTools немного загадочен). - person JayC; 06.03.2014
comment
Проверьте прослушиватели событий on, чтобы убедиться, что в одном из них нет ссылки на коллекцию... - person David Sulc; 06.03.2014
comment
Я не использую on, только listenTo, чтобы гарантировать, что Marionette/Backbone очистит за меня. - person JayC; 06.03.2014
comment
Кажется, я нашел утечку. Удаление моделей, как вы предложили, оставляет только ссылки системы (GC,bound_this и т. д.) и исходное составное представление, на которое ссылается только система, поэтому я предполагаю, что Chrome плохо обрабатывает эти ссылки. - person JayC; 06.03.2014

Если все это происходит внутри одного контроллера, т.е. контроллер все еще открыт и будет отвечать за событие, а Application.vent не будет запущен, я думаю, что эта ситуация приемлема, если утечка памяти не будет большой. Причина в том, что контроллер будет окончательно закрыт, так что не нужно торопиться.

Если будет запущено сообщение/запрос/команда на уровне приложения, вы должны отнестись к этому серьезно. Предположим, у вас есть такой код в контроллере:

@listenTo storiesView, 'itemview:show:button:clicked', (itemView) ->
  App.vent.trigger 'show:another:view:with:this:model', itemView.model

Остановись здесь. Модель является старой моделью и не будет собирать мусор.

Вместо этого я буду использовать приведенный ниже код:

@listenTo storiesView, 'itemview:show:button:clicked', (itemView) ->
  model = _.clone itemView.model
  App.vent.trigger 'show:another:view:with:this:model', model

Новая модель является совершенно новым объектом и не имеет ничего общего с текущим представлением/моделью/контроллером.

person Billy Chan    schedule 05.03.2014
comment
Я согласен с повторным использованием модели, я думаю, что это даже лучше, так как вам не нужно выделять новую память. Проблема заключается в атрибуте коллекции внутри модели. - person JayC; 06.03.2014