backbone.js - Fuga de memoria al eliminar elementos del DOM utilizando la red troncal
backbone-layout-manager (1)
Hay varios problemas con su código:
Utiliza
this.$el
como modelo para activar el eventoremove-item
. Deberías usar tu modelo en su lugar.La vista debe esperar a que los eventos del modelo sepan cuándo eliminarse.
Aquí está el código que se me ocurre. Si no funciona, publique su código en alguna parte para que pueda ejecutarlo yo mismo.
var ViewToDelete = Backbone.View.extend({ template: "ViewToDelete", tagName: "li", events: { "click .delete-button": "deleteItem" }, initialize: function () { this.listenTo(this.model, ''remove'', this.remove); }, deleteItem: function() { this.model.remove(); } });
La implementación predeterminada de view.remove()
eliminará this.$el
y dejará de escuchar el modelo:
remove: function() { this.$el.remove(); this.stopListening(); return this; },
EDITAR : Gracias por publicar su código en línea. Esto es lo que creo que está sucediendo (también estoy documentando para futuros espectadores).
Si toma una instantánea, filtre en el árbol DOM independiente, verá:
La parte importante es el árbol de retención: referencias que evitan que se elimine LI. Lo único significativo es sizzle-1364380997635
. No proviene de su código, en realidad proviene de jQuery, más específicamente de su motor Sizzle. La clave viene de aquí:
https://github.com/jquery/sizzle/blob/master/sizzle.js#L33
Si miras más allá en el código, ves que hay un caché:
https://github.com/jquery/sizzle/blob/master/sizzle.js#L1802
Entonces, en pocas palabras, tu código no tiene fugas, pero jQuery tiene un caché interno que evita que se elimine de todos modos. Este caché solo puede contener unas pocas docenas de elementos, por lo que no conservará los elementos para siempre.
Tengo problemas con los elementos DOM que quedan en la memoria después de eliminarlos. Configuré un ejemplo que se muestra a continuación. Tenga en cuenta que estoy usando el complemento administrador de diseño de red troncal para administrar mis vistas (así como jQuery).
He hecho una instantánea de Heap en Chrome antes y después de eliminar uno de los elementos de la lista y comparé los dos:
Como puede ver, el elemento LI todavía está en la memoria.
Backbone Layout Manager llama a view.unbind () y view.stopListening () cuando se elimina una vista.
A continuación está el código de ejemplo.
ListOfViewsToDelete.js
var TestModel = Backbone.Model.extend({
});
var TestCollection = Backbone.Collection.extend({
model: TestModel,
});
var ViewToDelete = Backbone.View.extend({
template: "ViewToDelete",
tagName: "li",
events: {
"click .delete-button": "deleteItem"
},
deleteItem: function() {
this.$el.trigger(''remove-item'', [this.model.id]);
}
});
var ListOfViewsToDelete = Backbone.View.extend({
template: "ListOfViewsToDelete",
initialize: function() {
this.collection = new TestCollection();
for (var i = 0; i < 5; i++) {
this.collection.add(new TestModel({id: i}));
}
this.listenTo(this.collection, ''all'', this.render);
},
events: {
"remove-item": "removeItemFromCollection"
},
beforeRender: function() {
this.collection.each(function(testModel) {
this.insertView("ul", new ViewToDelete({
model: testModel
}));
}, this);
},
removeItemFromCollection: function(event, model) {
this.collection.remove(model);
}
});
router.js
app.useLayout("MainLayout").setViews({
"#main": new ListOfViewsToDelete()
}).render();
ListOfViewsToDelete.html
<ul>
</ul>
ViewToDelete.html
View to delete
<button class="delete-button">x</button>