web-dev-qa-db-fra.com

Si un élément DOM est supprimé, ses écouteurs sont-ils également supprimés de la mémoire?

Si un élément DOM est supprimé, ses écouteurs sont-ils également supprimés de la mémoire?

298
nimrod

Navigateurs modernes

JavaScript simple

Si un élément DOM supprimé est dépourvu de références (aucune référence pointant vers lui), alors yes - l'élément lui-même est récupéré par le garbage collector en tant que ainsi que tous les gestionnaires d’événements/écouteurs qui lui sont associés.

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.

Pourtant; s'il y a des références qui pointent toujours vers ledit élément, l'élément et ses écouteurs d'événement sont conservés en mémoire.

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

Il serait juste de supposer que les méthodes pertinentes dans jQuery (telles que remove()) fonctionneraient exactement de la même manière (considérant que remove() a été écrit en utilisant removeChild() par exemple).

Cependant, ce n'est pas vrai ; la bibliothèque jQuery a en fait une méthode interne (non documentée et pouvant théoriquement être modifiée à tout moment) appelée cleanData()(voici à quoi ressemble cette méthode ) qui nettoie automatiquement toutes les données/événements associés à un élément lors de son retrait du DOM (que ce soit via. remove(), empty(), html("") etc.).


Vieux navigateurs

Les anciens navigateurs - en particulier les anciennes versions de IE - sont connus pour avoir des problèmes de fuite de mémoire en raison du fait que les écouteurs d'événements conservent des références aux éléments auxquels ils étaient attachés.

Si vous souhaitez une explication plus détaillée des causes, des schémas et des solutions utilisés pour corriger les fuites de mémoire héritées de la version IE, je vous recommande vivement de lire this Article MSDN sur la compréhension et la résolution des schémas de fuite d’Internet Explorer.

Quelques autres articles pertinents à ce sujet:

Supprimer manuellement les auditeurs vous-même serait probablement une bonne habitude à prendre dans ce cas (uniquement si la mémoire est vitale pour votre application et si vous ciblez de tels navigateurs).

270
lifetimes

concernant jQuery:

la méthode .remove () extrait des éléments du DOM. Utilisez .remove () lorsque vous souhaitez supprimer l'élément lui-même, ainsi que tout ce qu'il contient. Outre les éléments eux-mêmes, tous les événements liés et les données jQuery associées aux éléments sont supprimés. Pour supprimer les éléments sans supprimer les données et les événements, utilisez plutôt .detach ().

Référence: http://api.jquery.com/remove/

jQuery v1.8.2 .remove() code source:

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;
}

apparemment jQuery utilise node.removeChild()

Selon ceci: 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.

par exemple, les écouteurs d'événement peuvent être supprimés, mais node existe toujours en mémoire.

21
Sreenath S

J'étends juste d'autres réponses ...

Les gestionnaires d'événements délégués ne seront pas supprimés lors du retrait d'éléments.

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM

Maintenant, vérifiez:

$._data(document.body, 'events');
8
Lucky Soni

N'hésitez pas à regarder le tas pour voir les fuites de mémoire dans les gestionnaires d'événements gardant une référence à l'élément avec une fermeture et l'élément conservant une référence au gestionnaire d'événements.

Garbage Collector n'aime pas les références circulaires.

Cas de fuite de mémoire habituel: admettre qu'un objet a une référence à un élément. Cet élément a une référence au gestionnaire. Et le gestionnaire a une référence à l'objet. L'objet a des références à beaucoup d'autres objets. Cet objet faisait partie d'une collection que vous pensez avoir jetée en le retirant de votre collection. => tout l'objet et tout ce qui y est référé resteront en mémoire jusqu'à la sortie de la page. => vous devez penser à une méthode de destruction complète pour votre classe d'objet ou faire confiance à un framework MVC par exemple.

De plus, n'hésitez pas à utiliser la partie relative à la conservation de l'arborescence de Chrome outils de développement.

7
lib3d

En ce qui concerne jQuery, les méthodes courantes suivantes vont également supprimer d'autres constructions telles que les gestionnaires de données et d'événements:

remove ()

Outre les éléments eux-mêmes, tous les événements liés et les données jQuery associées aux éléments sont supprimés.

vide ()

Pour éviter les fuites de mémoire, jQuery supprime d'autres constructions telles que les gestionnaires de données et d'événements des éléments enfants avant de supprimer les éléments eux-mêmes.

html ()

De plus, jQuery supprime d'autres constructions telles que les gestionnaires de données et d'événements des éléments enfants avant de remplacer ces éléments par le nouveau contenu.

6
Jaskey

Oui, le ramasse-miettes les enlèvera également. Cela ne sera peut-être pas toujours le cas avec les anciens navigateurs.

2
Darin Dimitrov