Backbone.js - Должны ли вложенные представления поддерживать ссылки друг на друга?

Если представление Backbone View создает новые представления внутри метода render(), должны ли эти представления поддерживаться как члены данных? Типичный метод визуализации выглядит так:

render: function() {
  var myView = new MyView({ model: values });
  $('div#value', this.el).append(myView.render().el);
}

Этот тип привязки методов рендеринга означает, что вложенный вид действительно создан только так, что он также может связывать любые методы рендеринга и возвращать красиво сконструированный элемент. Представление осталось для сбора мусора, я предполагаю?

Если вложенный вид должен быть изменен... возможно, сильно, должен ли он быть просто (повторно) создан или должен быть изменен через ссылку на данные?

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

Я действительно не хочу, чтобы лучшие начинали бросать слушателей повсюду. И передавая ссылки на родительские представления и вызывается render() из дочернего объекта View, возникает утечка памяти, так как родитель создает новый дочерний вид, в то время как исходный дочерний элемент View поддерживает ссылку на родителя!

Он просто не очень похож на настоящий момент. У кого-нибудь есть какие-то ресурсы, которые помогли бы мне решить эту проблему в кадровой работе?

Ответ 1

(предупреждение: мой ответ стал трактатом tl; dr)

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

Большая проблема с обучением основы заключается в том, что она настолько непригодна и может использоваться (и используется) разными способами, что трудно понять, как сделать что-то "правильно" или, по крайней мере, в хорошем смысле, когда вы начинаем. Существует не только один истинный способ использования магистрали, но ее гибкость делает ее потрясающей структурой практически для любого приложения, и, надеюсь, я могу помочь в предоставлении некоторых рекомендаций. (Я мог бы, вероятно, приложить "ИМО" к каждому предложению здесь).

Во-первых, мое понимание представлений о магистралях

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

Обычно у меня есть один или несколько "корневых" представлений. Представления на уровне корня часто являются местом для инициализации, визуализации и хранения ссылок на дочерние представления, которые обрабатывают определенные части страницы. el представления на уровне корня часто является "телом" или другим элементом высокого уровня внутри тела. В некоторых случаях представление на корневом уровне имеет собственный HTML-код для наблюдения и/или рендеринга. В других случаях представление на уровне корня может вообще не иметь el и просто управляет дочерними представлениями. Я сохраняю ссылку на каждый вид корневого уровня (часто есть только один) в глобальном объекте пространства имен приложения.

В дополнение к представлениям "root-level" обычно есть "дочерние представления". Представление child инициализируется и визуализируется "родительским" представлением, которое может представлять собой представление на уровне корня или другое дочернее представление. Родительские взгляды отвечают за инициализацию, визуализацию, скрытие, показ и/или уничтожение своих детей по мере необходимости. Иногда родительское представление может отслеживать переменное количество экземпляров дочернего представления (например, в PlaylistView есть N SongViews). Часто родители поддерживают ссылки на детей, но иногда это не нужно (подробнее об этом ниже).

В дополнение к парадигме "root-level/parent/child" я склонен рассматривать представления в одной из двух категорий: (1) static: означает, что после инициализации представления вид и его el придерживайтесь, даже если в нем меняется материал; и (2) динамические, которые приходят и уходят, основываясь на различных событиях. Как правило, мои представления на уровне корня всегда статичны. Они также обычно соответствуют существующему элементу DOM, например, "body" или "my-div". Виды детей часто являются динамическими, но могут быть и статическими. (Советы: используйте el: '#element-id' для использования существующего элемента DOM как el при объявлении статического представления. Динамические представления обычно не указывают существующий el, они используют tagName id и className для описания элемент, который будет генерировать динамический вид.)

В представлениях по существу есть 3 функции: (1) выдавать себя и своих детей, когда им сообщают об этом их родителями или в ответ на события (или в случае представления на корневом уровне при инициализации маршрутизатором или " основная функция и т.д.), (2) реагировать на события пользовательского интерфейса из элементов DOM в пределах el (но не в пределах el любого дочернего представления) путем обновления моделей или коллекций или запуска пользовательских событий с базой и (3 ) наблюдать и реагировать на события Backbone (модель, коллекция и т.д.), которые требуют, чтобы что-то отображалось или изменялось в пределах их el (но не внутри el любого дочернего представления). Иногда бывает полезно, что дочерние представления могут инициировать события (this.trigger('customEvent')), что родительские представления могут наблюдать (childView.on('customEvent', this.handler, this)).

Дополнительные интересные перспективы на моделей магистральная зрения см: это и это.

Теперь в этом контексте, на вопросы

1) Страх сбора мусора, объема и утечек памяти

Если вы создаете дочерний вид в виде локального var в родительском рендере (или другом) методе и выполняете его, а затем функция выходит за рамки, я могу понять ваш страх перед сборкой мусора или что представление не будет быть в состоянии делать то, что нужно. Не нужно бояться сборщика мусора, просто зомби. Если ваше представление имеет какие-либо обработчики событий, независимо от того, объявлены ли обработчики событий пользовательского интерфейса в объявлении "события" или привязки к другим событиям объектов Backbone или другим прослушивателям событий на основе DOM, ваше представление не будет собираться с мусором, t больше ссылается на него - он все равно будет существовать в памяти и реагировать на события. С другой стороны, если в представлении нет обработчиков событий, то его единственным заданием является рендеринг элемента, поэтому кто заботится, будет ли объект javascript, который его отображает, - это, вероятно, будет сбор мусора, потому что он должен быть, См. this, для лучшего понимания коллекции мусора js в целом и того, как она относится к Backbone.js.

Большую озабоченность вызывает Zombie views. Если виды должны быть удалены из DOM и по существу отброшены в какой-то момент вашего приложения, убедитесь, что они либо полностью удаляются, либо что родительские представления должны содержать ссылку на них и удалять их. И не создавайте и не создавайте и не заменяйте созданные ранее представления и не удаляйте их должным образом. Удаление выполняется путем вызова функции .remove() в представлении, а также отмена любых внешних событий Backbone, которые вы ранее связывали, используя on(...) с помощью off(...). Недавние версии (1.0+) Backbone облегчают эту проблему, добавляя к прототипу View методы "listenTo" и "stopListening" . Понимать и использовать эти методы вместо включения/выключения, если вы динамически добавляете представления в DOM и из него. Совет. Настройка взломанного jquery "удалить" событие, подобного этому, может легко разрешить просмотр автономно удалять и очищать себя, когда их el удаляется из DOM (в случае, если в потоке приложения нет события, которое может служить той же цели).

2) Должны ли дочерние представления поддерживаться как элементы данных родительских представлений?

Это зависит. Я не думаю, что родительские взгляды, осознающие их взгляды на детей в ограниченных целях, нарушают любые золотые принципы MVC. Иногда родитель, имеющий ссылки на определенные экземпляры дочерних представлений, является отличным способом управления дочерними представлениями, если/когда вам это нужно. Как я указывал, иногда родительские представления реагируют на события, которые требуют от них рендеринга, повторной рендеринга, скрыть или удалить их дочерние представления. Иногда они могут захотеть прослушать события, которые дочерние представления запускаются сами по себе. Родители, однако, не должны слишком вовлекаться во что-либо внутри своих детских представлений el.

Тем не менее, не злоупотребляйте этими типами ссылок. Много раз вам не нужно будет использовать ссылки на детские представления, потому что дети могут позаботиться о себе. Как я уже упоминал, просмотры, однажды сделанные, должны только A) наблюдать за событиями пользовательского интерфейса внутри их el (но обычно не внутри какого-либо дочернего вида el) и обновлять модели или коллекции или запускать события в ответ на эти события пользовательского интерфейса, или B) наблюдать за события от других магистральных объектов (обычно модели или коллекции или другие представления) и предпринимать действия (например, обновлять свои собственные элементы пользовательского интерфейса) в ответ. Во многих случаях представление может заботиться о себе и даже удалять себя. Если другой View или другой объект Backbone заботится о событии пользовательского интерфейса, которое происходит в вашем представлении, обновите модель или инициируйте событие на представлении и дайте им возможность наблюдать за ним. Аналогично, если что-то вне вашего представления требует обновленного рендеринга в вашем представлении, слушайте изменение модели или подождите соответствующего пользовательского события. Как общий принцип, взгляды должны быть блаженно не знакомы друг с другом, за исключением родителей, которые обращают внимание на своих детей, когда это имеет смысл.

3) Должны ли представления ребенка поддерживать ссылки на родительские представления?

Нет. Никогда. Я не могу придумать ни одного сценария, где вам нужно было бы что-то сделать с помощью ссылки на родителя, которая не может быть достигнута путем изменения модели, которую наблюдает родитель, или инициирования события (например, пользовательское событие, говорящее "hey, X произошло" ) на самом детском представлении или на другом базовом объекте "События". В Backbone я использую модели для представления как моих данных, так и моего состояния. Поэтому, если что-то происходит в представлении, которое меняет состояние моего приложения, я затем изменяю соответствующий атрибут состояния модели и позволяю другим представлениям (включая родителя) прислушиваться к автоматическому событию "change", если они им нравятся. Я также использую глобальный "вентиляционный" подобный шине объект (просто базовый объект javascript, который расширяет Backbone.Events) для запуска и прослушивания событий в приложении, а иногда я запускаю события непосредственно в представлениях, чтобы родительские объекты знали, что что-то произошло, Независимо от того, что работает, сохраняя при этом вашу архитектуру как можно распутанную.

4) Я действительно не хочу, чтобы топ-старт бросал слушателей повсюду.

Хорошо, я думаю, что одна хорошая вещь о позвоночнике - это то, что вам не нужно, но осознайте, что шаблон Observer (т.е. события и слушатели) и свободная связь являются основой базового аромата MVC (обратите внимание, что каждая отдельная опорная линия class extends Events?), и большинство людей используют его соответствующим образом.

Ссылки

Я настоятельно рекомендую учебники PeepCode, если вы не чувствуете, что уже находитесь на довольно продвинутом уровне. 12 баксов кусок, но вам нужно начать с первого или второго и третьего не будет очень полезно.

Кроме того, вот хороший обзор.

Конец