Respuestas:
JavaScript simple
Si un elemento DOM que se elimina no tiene referencias (no hay referencias que lo señalen), entonces sí , el elemento en sí es recogido por el recolector de basura, así como por cualquier controlador / escucha de eventos asociado con él.
var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null;
// A reference to 'b' no longer exists
// Therefore the element and any event listeners attached to it are removed.
Sin embargo; Si hay referencias que todavía apuntan a dicho elemento, el elemento y sus oyentes de eventos se retienen en la memoria.
var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
// A reference to 'b' still exists
// Therefore the element and any associated event listeners are still retained.
jQuery
Sería justo suponer que los métodos relevantes en jQuery (como remove()
) funcionarían exactamente de la misma manera (considerando que remove()
se escribió usando, removeChild()
por ejemplo).
Sin embargo, esto no es cierto ; la biblioteca jQuery en realidad tiene un método interno (que no está documentado y en teoría podría cambiarse en cualquier momento) llamado cleanData()
(así es como se ve este método ) que limpia automáticamente todos los datos / eventos asociados con un elemento al eliminarlo del DOM (ya sea a través de este. remove()
, empty()
, html("")
etc).
Se sabe que los navegadores más antiguos, específicamente las versiones anteriores de IE, tienen problemas de pérdida de memoria debido a que los oyentes de eventos mantienen referencias a los elementos a los que se adjuntaron.
Si desea una explicación más detallada de las causas, los patrones y las soluciones utilizadas para corregir las pérdidas de memoria de la versión IE heredada, le recomiendo que lea este artículo de MSDN sobre Comprender y resolver patrones de fugas de Internet Explorer.
Algunos artículos más relevantes para esto:
Eliminar manualmente los oyentes probablemente sea un buen hábito en este caso (solo si la memoria es tan vital para su aplicación y realmente está apuntando a tales navegadores).
remove
método. la mayoría de las veces el DOM simplemente se borrará por completo. (como enlaces turbo o algo así). Me pregunto cómo se ve afectada la memoria si lo hago document.body.innerHTML = ''
...
con respecto a jQuery:
El método .remove () elimina elementos del DOM. Use .remove () cuando desee eliminar el elemento en sí, así como todo lo que contiene. Además de los elementos en sí, se eliminan todos los eventos vinculados y los datos jQuery asociados con los elementos. Para eliminar los elementos sin eliminar datos y eventos, use .detach () en su lugar.
Referencia: http://api.jquery.com/remove/
Código .remove()
fuente de jQuery v1.8.2 :
remove: function( selector, keepData ) {
var elem,
i = 0;
for ( ; (elem = this[i]) != null; i++ ) {
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
if ( !keepData && elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
jQuery.cleanData( [ elem ] );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
}
return this;
}
aparentemente jQuery usa node.removeChild()
De acuerdo con esto: https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,
The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.
es decir, los oyentes de eventos pueden ser eliminados, pero node
aún existe en la memoria.
removeChild
no lo haría. Ambos también le devuelven una referencia que puede mantener para volver a unir este último (en cuyo caso, obviamente, permanece en la memoria) o tirar (en cuyo caso finalmente es recogido por GC y eliminado).
No dude en ver el montón para ver pérdidas de memoria en los controladores de eventos que mantienen una referencia al elemento con un cierre y el elemento que mantiene una referencia al controlador de eventos.
Al recolector de basura no le gustan las referencias circulares.
Caso habitual de pérdida de memoria: admitir que un objeto tiene una referencia a un elemento. Ese elemento tiene una referencia al controlador. Y el controlador tiene una referencia al objeto. El objeto tiene referencias a muchos otros objetos. Este objeto era parte de una colección que crees que has tirado al no hacer referencia a ella desde tu colección. => todo el objeto y todo lo que hace referencia permanecerá en la memoria hasta que salga la página. => debe pensar en un método de eliminación completo para su clase de objeto o confiar en un marco de mvc, por ejemplo.
Además, no dude en utilizar la parte del árbol de retención de las herramientas de desarrollo de Chrome.
Solo extendiendo otras respuestas ...
Los controladores de eventos delegados no se eliminarán al eliminar elementos.
$('body').on('click', '#someEl', function (event){
console.log(event);
});
$('#someEL').remove(); // removing the element from DOM
Revisa ahora:
$._data(document.body, 'events');
En cuanto a jQuery
, los siguientes métodos comunes también eliminarán otras construcciones, como los controladores de datos y eventos:
Además de los elementos en sí, se eliminan todos los eventos vinculados y los datos jQuery asociados con los elementos.
Para evitar pérdidas de memoria, jQuery elimina otras construcciones, como los manejadores de datos y eventos, de los elementos secundarios antes de eliminar los elementos mismos.
Además, jQuery elimina otras construcciones como datos y controladores de eventos de elementos secundarios antes de reemplazar esos elementos con el nuevo contenido.
Sí, el recolector de basura también los eliminará. Sin embargo, no siempre puede ser el caso con los navegadores heredados.