2012-04-09 11 views
20

Si una vista de red troncal crea nuevas vistas dentro de su método render(), ¿estas vistas se deben mantener como miembros de datos? Un método típico hacer que se parece a:Backbone.js - ¿Las vistas anidadas deben mantener referencias entre ellas?

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

Este tipo de encadenamiento de métodos rendir significa que el anidado vista es realmente sólo creó por lo que también puede encadenar cualquier render métodos y devolver un elemento muy bien construido. La vista se deja para la recolección de basura, supongo?

Si la Vista anidada se va a modificar ... tal vez en gran medida, ¿debería simplemente (re) crearse, o debería modificarse a través de la referencia de miembro de datos?

El problema que tengo es que las Vistas anidadas reciben eventos que requieren que modifiquen sus propias Vistas anidadas, y alguna vez su Vista padre.

Realmente no quiero empezar a lanzar oyentes por todas partes. Y al pasar referencias a Vistas padre y a invocado render() desde la vista secundaria se produce una fuga de memoria ya que el padre crea una nueva Vista hijo mientras la Vista secundaria original mantiene una referencia a su padre.

No es muy parecido a un framework en este momento. ¿Alguien tiene algún recurso que me ayude a resolver este problema de la misma manera?

+1

Los cierres y objetos que no tienen referencias vivas o fijaciones en cualquier lugar a ellas (en esencia, a la espera de ser basura recogida) no causará una pérdida de memoria sólo porque tienen referencia a algo que existe, al menos, no estoy enterado de ningún esquema de recolección de basura ... ciertamente algunos motores de recolección de basura no funcionarán bien con referencias cíclicas (sin manejar manualmente las referencias) pero javascript usa Marcar y Barrido, y eso maneja referencias cíclicas muy bien . Los peores problemas de AFAIK se deben a referencias cruzadas entre el DOM y el javascript "world" por así decirlo. – JayC

Respuesta

44

(advertencia: mi respuesta se convirtió en un tl; dr tratado)

que tenían algunas de estas mismas preguntas desde el principio, y se han hecho los deberes con el fin de construir algunas aplicaciones muy complejas, por lo que voy a ofrecer mi perspectiva.

El gran reto del aprendizaje de la red troncal es que es muy poco sofisticado y se puede (y se usa) de muchas maneras diferentes que es difícil saber cómo hacer algo "correcto" o al menos en el buen sentido cuando estás comenzando. No hay una sola forma verdadera de utilizar la red troncal, pero su flexibilidad la convierte en una estructura asombrosa para casi cualquier aplicación, y espero que pueda ayudarlo a proporcionar alguna orientación. (Probablemente podría adjuntar "IMO" a cada oración aquí).

En primer lugar, mi comprensión de la columna vertebral ve

En aplicaciones backbone, hay un montón de maneras útiles para utilizar puntos de vista. Generalmente veo algunos tipos de vistas superpuestas en mis aplicaciones:

Normalmente tengo una o más vistas de "nivel raíz". Las vistas de nivel raíz a menudo son un lugar para inicializar, representar y mantener referencias a vistas secundarias que manejan partes específicas de la página. El el de una vista de nivel raíz a menudo es "cuerpo" u otro elemento de alto nivel dentro del cuerpo. En algunos casos, una vista de nivel de raíz tiene su propio HTML para observar y/o representar. En otros, una vista de nivel de raíz puede no tener el y solo administra vistas secundarias. Guardo una referencia a cada vista de nivel de raíz (a menudo solo hay una) en un objeto de espacio de nombres 'aplicación' global.

Además de las vistas de "nivel raíz", normalmente hay "vistas secundarias". Una vista secundaria se inicializa y representa mediante una vista "principal", que puede ser una vista de nivel raíz u otra vista secundaria. Las vistas de los padres son las encargadas de inicializar, renderizar, ocultar, mostrar y/o destruir a sus hijos según lo requiera la aplicación. A veces, una vista principal puede realizar un seguimiento de un número variable de instancias de una Vista secundaria (por ejemplo, una PlaylistView tiene N SongViews). A menudo, los padres mantienen referencias a los niños, pero a veces es innecesario (más sobre esto a continuación).

Además del paradigma 'nivel raíz/padre/hijo', tiendo a ver las vistas en una de dos categorías: (1) estático: significa que una vez que se inicializa la vista, la vista y su el alrededor, incluso si las cosas cambian dentro de ella; y (2) dinámicos, que van y vienen, basados ​​en varios eventos. Por lo general, mis vistas de nivel raíz son siempre estáticas. También suelen corresponder a un elemento DOM existente, por ejemplo, 'cuerpo' o '# my-div'. Las vistas secundarias suelen ser dinámicas, pero también pueden ser estáticas. (. Consejos: usar el: '#element-id' utilizar un elemento DOM existente como el al declarar una visión estática vistas dinámicas normalmente no especifican un el existentes, que utilizan tagNameid y className para describir el elemento que la visión dinámica generará.)

Las vistas tienen esencialmente 3 funciones: (1) renderizan ellas mismas y sus hijos cuando sus padres o en respuesta a los eventos (o en el caso de una vista de nivel raíz, cuando son inicializadas por un enrutador o un 'main 'función, etc.), (2) responden a eventos UI de elementos DOM dentro de sus el (pero no dentro de el de cualquier vista secundaria) actualizando modelos o colecciones o activando eventos Backbone personalizados, y (3) observando y respondiendo Backbone (mod el, colección, etc.) eventos que requieren que se represente o cambie algo dentro de su el (pero no dentro del el de cualquier vista secundaria). Un truco a veces útil es que las vistas secundarias pueden desencadenar eventos en sí mismos (this.trigger('customEvent')) las vistas pueden observar (childView.on('customEvent', this.handler, this)).

Para obtener perspectivas interesantes adicionales sobre los patrones de vista de red troncal, consulte: this y this.

Ahora bien, en ese contexto, a preguntas

1) El miedo a la recolección de basura, el alcance y de pérdidas de memoria

Si usted instancia una vista niño como var en una matriz de render (u otro) método y renderizarlo, y luego la función queda fuera del alcance, puedo entender su miedo a la recolección de basura o que la vista no podrá hacer lo que debe hacer. No hay necesidad de temer al recolector de basura, solo a los zombis. Si su vista tiene algún manejador de eventos, si los manejadores de eventos UI declararon en la declaración de "eventos", o enlaces a otros eventos de objetos Backbone, u otros escuchas de eventos basados ​​en DOM, su vista no será recolectada aunque no lo haga Ya tengo una referencia a él: todavía existirá en la memoria y responderá a los eventos. Por otro lado, si una vista no tiene ningún manejador de eventos, entonces su único trabajo es representar un elemento, así que ¿a quién le importa si el objeto javascript que lo renderizó se queda? Probablemente será basura recolectada porque debería ser . Ver this, para una gran comprensión de la recolección de basura js en general y cómo se relaciona con Backbone.js.

La mayor preocupación es de Zombie views. Si las vistas deben ser eliminadas del DOM y esencialmente descartadas en algún momento de su aplicación, asegúrese de que se eliminen por completo o que las vistas padre mantengan una referencia a ellas y las eliminen. Y no vuelva a crear y reemplazar vistas que ya se hayan creado y no se hayan eliminado correctamente. La eliminación se realiza al invocar .remove() en la vista, además de desvincular cualquier evento Backbone externo que haya sido previamente vinculado usando on(...) usando off(...). Las versiones recientes (1.0+) de Backbone hacen que este problema se solucione más fácilmente al agregar "listenTo" and "stopListening" methods al prototipo de View. Comprenda y use estos métodos en lugar de activar/desactivar si agrega dinámicamente las vistas hacia y desde el DOM. Consejo: La configuración de un a hacky jquery "remove" event like this one puede permitir fácilmente que las vistas se eliminen y se limpien automáticamente cuando se elimine su el del DOM (en caso de que no haya un evento en el flujo de la aplicación que pueda servir para el mismo propósito).

2) ¿Deberían mantenerse las vistas secundarias como datos de las vistas padre?

Depende. No creo que los puntos de vista de los padres sean conscientes de las opiniones de sus hijos con propósitos limitados, viola los principios dorados de MVC. A veces, un padre que tenga referencias de miembro a instancias específicas de vista secundaria es una excelente manera de administrar vistas secundarias si lo necesita. Como indiqué, algunas veces las vistas principales responden a eventos que requieren que las mismas rendericen, vuelvan a renderizar, oculten o eliminen sus vistas secundarias. En ocasiones, es posible que deseen escuchar los eventos que las visualizaciones secundarias desencadenan sobre ellos mismos. Los padres, sin embargo, no deberían involucrarse demasiado en cualquier cosa dentro de las vistas de sus hijos 'el's.

Dicho esto, no abuse de este tipo de referencias. Muchas veces, no necesitará usar referencias a vistas de niños, porque los niños pueden cuidarse solos. Como mencioné, las vistas, una vez renderizadas, solo deberían A) observar los eventos UI dentro de su el (pero normalmente no dentro de ninguna vista secundaria) y actualizar modelos o colecciones o desencadenar eventos en respuesta a estos eventos UI, o B) observar eventos de otros objetos troncales (generalmente modelos o colecciones u otras vistas) y tomar acciones (por ejemplo, actualizar sus propios elementos UI) en respuesta. En muchos casos, una vista puede cuidarse e incluso eliminarse. Si otro objeto Vista u otro objeto Backbone se preocupa por que ocurra un evento UI en su vista, actualice un modelo o active un evento en la vista y permita que lo observen. Del mismo modo, si algo fuera de su vista requiere una representación actualizada en su vista, escuche el cambio en un modelo o espere un evento personalizado correspondiente. Como principio general, los puntos de vista deben ser felizmente ajenos el uno al otro, con la excepción de que los padres se preocupen por sus hijos cuando tenga sentido.

3) ¿Deberían las vistas secundarias mantener referencias a vistas padre?

No. Never. No puedo pensar en un solo escenario en el que necesite lograr algo a través de una referencia a un padre que no podría lograrse cambiando un modelo que el padre está observando o desencadenando un evento (por ejemplo, un evento personalizado que dice "hey, X happen") en la vista hija o en otro objeto basado en "Eventos". En Backbone, uso modelos para representar mis datos Y mi estado. Entonces, si sucede algo en una vista que cambie el estado de mi aplicación, entonces cambio el atributo de estado correspondiente de un modelo y dejo que otras vistas (incluido el padre) escuchen el evento de "cambio" automático si les importa. También utilizo un objeto similar a un bus "vent" global (solo un objeto javascript básico que amplía Backbone.Events) para activar y escuchar eventos en toda la aplicación, y algunas veces desencadenar eventos en Views para que los objetos padres sepan que sucedió algo . Lo que sea que funcione, mientras mantiene su arquitectura tan desenredada como sea posible.

4) Realmente no quiero empezar a lanzar oyentes por todas partes.

Bueno, creo que una buena cosa sobre la columna vertebral es que usted no tiene que, pero se da cuenta de que el patrón de observador (es decir, eventos & oyentes) y bajo acoplamiento están en el corazón de sabor de columna vertebral de MVC (noto que cada ¿la clase única de Backbone extiende los eventos?), y la mayoría de las personas la usan en consecuencia.

Referencias?

Recomiendo encarecidamente el PeepCode tutorials a menos que sienta que ya se encuentra en un nivel bastante avanzado. 12 dólares por pieza, pero debe comenzar con el primero o el segundo & tercero no será muy útil.

También, here's a nice overview.

El fin

+0

Gracias. Eso fue increíblemente útil. – user941521

+0

Bien puesto, @Ben R! +1: D –

+1

"Si su vista tiene algún manejador de eventos de cualquier tipo ... no será basura recolectada aunque ya no tenga una referencia, seguirá existiendo en la memoria y responderá a los eventos". ¡Algo a tener en cuenta al escribir pruebas unitarias! –

Cuestiones relacionadas