backbone.js - pixar - ¿Cuándo usar bindTo, bind o on con Backbone.Marionette?
marionette pixar (1)
la guía general es que cada vez que tenga un objeto creado y destruido durante la vida de la aplicación, y ese objeto deba vincularse a eventos de algún otro objeto, debe usar el EventBinder
.
Vistas y fugas de memoria
Las vistas son el ejemplo perfecto de esto. Las vistas se crean y se destruyen todo el tiempo. También se unen a muchos eventos diferentes del model
y la collection
en la vista. Cuando se destruye la vista, esos eventos deben ser limpiados. Al utilizar el método bindTo
en la vista, los manejadores de eventos se limpiarán por usted. Si no usa bindTo
y en su lugar lo usa directamente, tendrá que off
manualmente off
desvinculación de los eventos cuando la vista se cierre / destruya. Si no lo haces, terminarás con zombies (pérdidas de memoria).
Si aún no los has leído, mira estos artículos:
http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/
Agrupaciones de eventos personalizados
Sin embargo, las vistas no son el único lugar donde se aplica esto, y no es el único caso de uso para EventBinder
.
Si está trabajando con un puñado de objetos, vinculando a sus eventos, y esos objetos pueden ser reemplazados por otras instancias de objetos, entonces un EventBinder
sería útil. En este caso, piense en el EventBinder como una colección o grupo de eventos para objetos relacionados.
Digamos que tienes ObjA, ObjB y ObjC. Cada uno de estos dispara algunos eventos, y usted quiere asegurarse de limpiar los manejadores de eventos cuando su código esté listo. Esto es fácil con un EventBinder
:
doStuff = {
start: function(a, b, c){
this.events = new Marionette.EventBinder();
this.events.bindTo(a, "foo", this.doSomething, this);
this.events.bindTo(b, "bar", this.anotherThing, this);
this.events.bindTo(c, "baz", this.whatever, this);
},
doSomething: function(){ /* ... */ },
anotherThing: function(){ /* ... */ },
whatever: function(){ /* ... */ },
stop: function(){
this.events.unbindAll();
}
}
doStuff.start(ObjA, ObjB, ObjC);
// ... some time later in the code, stop it
doStuff.stop();
La stop
llamadas en este código limpiará correctamente todos los controladores de eventos para este uso.
Cuándo usar on
/ off
directamente
Lo contrario de todo esto, es decir que no siempre es necesario utilizar un EventBinder
. Puedes escapar sin él, siempre. Pero debes recordar limpiar tus eventos cuando sea necesario.
En situaciones en las que no es necesario limpiar los controladores de eventos, tampoco es necesario utilizar un EventBinder
. Este puede ser un evento que desencadena un enrutador o que desencadena el objeto Marionette.Application
. Para aquellos eventos del ciclo de vida de la aplicación, o eventos que necesitan vivir durante toda la vida de la aplicación, no se moleste con un EventBinder
. En su lugar, simplemente deje que los controladores de eventos vivan. Cuando la persona actualiza la ventana del navegador o navega a un sitio diferente, los manejadores se limpiarán en ese momento.
Pero cuando necesita administrar la memoria y los controladores de eventos, limpiar las referencias y cerrar las cosas sin actualizar la página o alejarse de ella, EventBinder
vuelve importante ya que simplifica la administración de eventos.
Esta vez estoy luchando con los diferentes métodos para enlazar eventos. Tengo todos los métodos mencionados en mi código. Simplemente no sé, si estoy en el camino correcto. ¿Tal vez debería usar bindTo siempre para asegurar que mis vistas se cierren completamente después de un cambio (en la actualidad esto a menudo generaría errores)? ¿Existen prácticas recomendadas que me ayuden a orientarme en la dirección correcta?
Para ilustrar mi comprensión actual de Marionette, aquí hay un módulo de mi aplicación. Como siempre, cada sugerencia es muy bienvenida.
PP.module(''Grid'', function(Grid, PP, Backbone, Marionette, $, _){
Grid.Product = Backbone.Model.extend({});
Grid.ProductCollection = Backbone.Collection.extend({
model: Grid.Product,
url: ''/products/query''
});
Grid.ProductView = Backbone.Marionette.ItemView.extend({
className: ''grid'',
template: ''public/templates/grid-template''
});
// Helper Methods
// -----------------------
var getGenderCode = function(genderName){
var genderMap = {
''men'': ''M'',
''women'': ''W'',
''unisex'': ''A''
}
return genderMap.genderName;
}
// Public API
// -------------------
Grid.renderGrid = function(productCollection){
Grid.productView = new Grid.ProductView({
collection: productCollection
});
Grid.productView.bind(''show'', function(){
$(''#isotope-container'').isotope({
itemSelector : ''.item'',
containerStyle: {
position: ''relative'',
zIndex: 1
}
});
});
PP.Layout.mainRegion.show(Grid.productView);
}
// Event Handlers
// -----------------------
PP.vent.bind(''grid:requested'', function(categoryData){
// use bootstrapped data on first start
if (PP.App.bootstrappedCategoryName !== categoryData.categoryName) {
Grid.productCollection.fetch({
data: {
gender: getGenderCode(categoryData.categoryName),
category: categoryData.categoryId
}
});
}
else {
PP.vent.trigger(''mainview:ready'', {
categoryName: PP.App.bootstrappedCategoryName
});
}
});
// Initializer
// --------------------
PP.addInitializer(function(options){
Grid.productCollection = new Grid.ProductCollection();
Grid.productCollection.on(''reset'', function(){
Grid.renderGrid(Grid.productCollection);
});
Grid.productCollection.reset(options.newArrivalsList);
});
});