mdn - memory leak javascript
fugas de memoria javascript (5)
Como se refiere constantemente a $ (''# parent''), debe crear una referencia a ese objeto en el ámbito global para que jQuery no busque constantemente el objeto en cada solicitud. Al hacer esto, esencialmente estás guardando en caché la referencia al objeto, lo que reducirá enormemente el uso de la memoria.
_parent = $(''#parent'');
...
function(){ _parent.append(''<span>1</span>''); }
Edit: Recogí este consejo de este artículo sobre las Reglas de rendimiento de jQuery
Estoy usando jquery y haciendo algo como esto
DOM
:
<div id="parent"></div>
JS
:
var _doSomeThing = function()
{
//some codes
}
$(function()
{
// appending div and binding methods to span
$(''#parent'').append(''<span>1</span>'');
$(''#parent'').append(''<span>2</span>'');
$(''#parent span'').bind(''click'', _doSomeThing);
});
function _clearDiv()
{
//clear div
$(''#parent'').html('''');
}
//sometime in future, call clear div
_clearDiv();
Ahora mi pregunta es, ¿los eventos de vinculación con DOM
y luego la eliminación de los elementos de DOM
llevan a una pérdida de memoria?
Si es así, ¿cómo solucionar este problema?
El método html
jQuery intenta evitar las fugas de memoria al eliminar los controladores de eventos para cualquier elemento que se elimine como resultado de llamar a .html('''')
en un objeto jQuery.
De la fuente 1.4.2
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
}
// See if we can take a shortcut and just use innerHTML
// THE RELEVANT PART
else if ( typeof value === "string" && !rnocache.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, fcloseTag);
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
}
catch(e) {
this.empty().append( value );
}
}
else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery(this), old = self.html();
self.empty().append(function(){
return value.call( this, i, old );
});
});
}
else {
this.empty().append( value );
}
return this;
}
Podemos ver que se llama a la función jQuery.cleanData()
. Aquí está la fuente para eso
cleanData: function( elems ) {
var data, id, cache = jQuery.cache,
special = jQuery.event.special,
deleteExpando = jQuery.support.deleteExpando;
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
id = elem[ jQuery.expando ];
if ( id ) {
data = cache[ id ];
if ( data.events ) {
for ( var type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
} else {
removeEvent( elem, type, data.handle );
}
}
}
if ( deleteExpando ) {
delete elem[ jQuery.expando ];
} else if ( elem.removeAttribute ) {
elem.removeAttribute( jQuery.expando );
}
delete cache[ id ];
}
}
}
Esto busca en el objeto jQuery.cache
cualquier propiedad de tipo de evento en la propiedad del objeto de eventos del objeto de datos relacionado con cada elemento que se eliminará al llamar a .html('''')
y los elimina.
Básicamente, para explicar cómo funciona el enlace de eventos estándar, cuando una función se vincula como un controlador a un evento generado en un elemento utilizando jQuery, se agrega un objeto de datos como una propiedad al objeto jQuery.cache
. Este objeto de datos contiene un objeto de propiedad de eventos que tendrá una propiedad creada con un nombre que coincide con el tipo de evento al que desea enlazar la función del controlador de eventos. esta propiedad contendrá una matriz de funciones que deben llamarse cuando el evento se genere en el elemento, por lo que la función del controlador de eventos se agrega a esta matriz. Si esta es la primera función de controlador de eventos para el tipo de evento y el elemento en cuestión, la función jQuery.event.handle
con una llamada a aplicar (usando el elemento como el contexto de manera que en el contexto de ejecución de la función se refiera al elemento) se registra con el navegador mediante addEventListener/attachEvent
.
Cuando se jQuery.event.handle
un evento, la función jQuery.event.handle
llamará a todas las funciones de la matriz en la propiedad del objeto de propiedad de eventos del objeto de datos que coincide con el tipo de evento y el elemento en el que se generó el evento.
Entonces, en resumen, html('''')
no debería causar pérdidas de memoria ya que existen varias medidas defensivas para prevenirlas.
No se puede comentar sobre el problema de fugas, pero simplemente puede usar .empty()
lugar de .html('''')
. De esa forma, limpiaría el innerHTML y eliminaría cualquier controlador de eventos enlazados.
Sí, porque jQuery mantiene una lista de los controladores de eventos adjuntos para facilitar la desconexión y para desengancharlos explícitamente cuando se descarga la página (lo que evita una pérdida de memoria más grave en IE). (Lo mismo ocurre con Prototype, no se puede hablar de otras librerías). La solución es desengancharlos antes de eliminar los elementos (ya sea directamente o por medio de un empty
).
Siempre puedes usar $(''#parent span'').unbind();
sólo para estar seguro