Ajouter / supprimer des auditeurs sur javascript (collecteur d'ordures)

J'ai une question rapide concernant l'ajout / suppression d'auditeurs d'un objet DOM. Je voudrais demander si le collecteur d'ordures peut collecter la mémoire lors de l'élimination des éléments de la page.

ex. Une <ul> avec une double liste d'enfants ( <li> )

 var ul = document.getElementById('someParent'); var children = ul.children; var someFunction = function() {}; for(var i = 0; i < children.length; i++) { children[i].addEventListener('click', someFunction); } // This is where I am not sure, would the garbage collector be able to collect // the memory allocated on adding listener on children, // if I remove the ul tag? ul.remove(); 

La ligne ul.remove(); ul élément ul et tous ses enfants du DOM. Mais la mémoire pour les auditeurs d'événements ne sera pas diffusée aussi longtemps que vous avez des références à ces auditeurs, éléments li et ul élément. Ce que vous avez dans les variables children , someFunction et ul .

Si vous souhaitez laisser le collecteur d'ordures nettoyer tout cela, vous pouvez le faire par exemple:

 ul.remove(); children = null; someFunction = null; ul = null; 

De cette façon, les children variables ne tiendront pas la référence à ces éléments, et si vous ne possédez pas d'autre variable dans votre code qui contient la référence pour ces éléments, le collecteur d'ordures les collectera. Il en va de même pour someFunction . Notez que l'élément ul contient toutes les références à ses enfants et ses auditeurs, il faut donc aussi nettoyer.

Pas du tout, vous pouvez accéder à la variable ul ailleurs. L'exemple ci-dessous montre cela.

 var ul = document.getElementById('someParent'); ul.remove(); console.log(ul); // ul and all li tags document.body.appendChild(ul); // ul appears again 

L'exemple n'est pas un cas normal. Le cas habituel est que vous souhaitez accéder à une référence DOM dans un événement, dites «clic bouton». Cette référence sera toujours disponible tant que l'événement ne sera pas délié. Par exemple:

 var ul = document.getElementById('someParent'); var myButton = document.getElementById('myButton'); myButton.addEventListener('click', function () { ul.innerHTML += '<li>Some text</li>' }); ul.remove(); myButton.click(); // no exception when execting button click event 

Pour éviter une fuite de mémoire dans JS:

  1. Assurez-vous qu'il n'y a pas de références DOM en utilisant jQuery par exemple.
  2. Si vous utilisez des références DOM dans votre application, définissez-les comme nuls ou non définis lorsqu'ils ne sont pas utilisés.

Ainsi, vous pouvez modifier votre événement un peu comme ci-dessous.

 myButton.addEventListener('click', function () { // check ul belongs to visible DOM if (!document.body.contains(ul)) { ul = null; return; } ul.innerHTML += '<li>Some text</li>' }); 

Si quelqu'un me le confirme, j'apprécierais cela.

D'après ce que je comprends, oui, ce seront les ordures collectées. Selon MDN Memory Management

La notion principale d'algorithmes de collecte des ordures s'appuie sur la notion de référence. Dans le contexte de la gestion de la mémoire, on dit qu'un objet fait référence à un autre objet si le premier a un accès à celui-ci (implicite ou explicitement). Par exemple, un objet JavaScript a une référence à son prototype (référence implicite) et à ses valeurs de propriétés (référence explicite).

Essentiellement, si le DOM ne peut pas trouver une référence à cet élément, il le récupérera dans un proche avenir. En regardant la spécification DOM standard de la façon dont .remove () fonctionne, elle exécutera une série d'étapes qui définiront les nouveaux index des parents et des frères et sœurs en supprimant toutes les références à l'élément.

Parce qu'il n'y a pas de références à cet élément, il sera collecté. Dans votre exemple, vous ajoutez eventListeners uniquement aux enfants de l'élément spécifique <ul> vous avez créé. Lorsque vous supprimez un élément, vous supprimez également toutes les références de ses enfants (je pense que cela est plus clair dans les étapes du lien ci-dessus où ils ont réellement défini l'indice parent pour se diriger vers lui-même).

EDIT: @contrabit est bien. Je ne vous ai pas vu stocker vos children dans une variable. Tant qu'ils sont une référence à eux, ils ne seront pas récupérés.