440 Stimmen

Wenn ein DOM-Element entfernt wird, werden auch seine Zuhörer aus dem Speicher entfernt?

Wenn ein DOM-Element entfernt wird, werden auch seine Zuhörer aus dem Speicher entfernt?

388voto

dsgriffin Punkte 64890

Moderne Browser

Einfaches JavaScript

Wenn ein DOM-Element, das entfernt wird, referenzfrei ist (keine Referenzen, die auf es zeigen), dann ja - das Element selbst wird vom Garbage Collector abgeholt, ebenso wie alle damit verbundenen Event-Handler/Listener.

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.

Gibt es jedoch Verweise, die noch auf das besagte Element verweisen, werden das Element und seine Ereignis-Listener im Speicher gehalten.

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

Es ist anzunehmen, dass die entsprechenden Methoden in jQuery (wie remove() ) würde auf genau dieselbe Weise funktionieren (unter Berücksichtigung remove() wurde geschrieben mit removeChild() zum Beispiel).

Allerdings, das ist nicht wahr Die jQuery-Bibliothek verfügt über eine interne Methode (die undokumentiert ist und theoretisch jederzeit geändert werden könnte), die cleanData() (so sieht diese Methode aus ), die automatisch alle Daten/Ereignisse bereinigt, die mit einem Element beim Entfernen aus dem DOM verbunden sind (sei dies über. remove() , empty() , html("") usw.).


Ältere Browser

Ältere Browser - insbesondere ältere Versionen des IE - sind dafür bekannt, dass sie Probleme mit Speicherlecks haben, weil Ereignis-Listener Verweise auf die Elemente behalten, an die sie angehängt waren.

Wenn Sie eine detailliertere Erklärung der Ursachen, Muster und Lösungen zur Behebung von Speicherlecks in älteren IE-Versionen wünschen, empfehle ich Ihnen die Lektüre diesen MSDN-Artikel über das Verstehen und Lösen von Internet Explorer-Leckmustern.

Einige weitere Artikel zu diesem Thema:

Manuelles Entfernen der Listener selbst wäre in diesem Fall wahrscheinlich eine gute Angewohnheit (nur wenn der Speicher für Ihre Anwendung so wichtig ist und Sie tatsächlich auf solche Browser abzielen).

24voto

Sreenath S Punkte 1269

Zu jQuery:

die Methode .remove() nimmt Elemente aus dem DOM. Verwenden Sie .remove(), wenn Sie auch das Element selbst entfernen wollen als auch alles darin. Zusätzlich zu den Elementen selbst, werden alle gebundenen Ereignisse und jQuery-Daten, die mit den Elementen verbunden sind, entfernt. Um die Elemente zu entfernen, ohne Daten und Ereignisse zu entfernen, verwenden Sie .detach() stattdessen.

Referenz: http://api.jquery.com/remove/

jQuery v1.8.2 .remove() Quellcode:

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

jQuery verwendet offenbar node.removeChild()

Nach diesem : 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.

d.h. Ereignis-Listener können entfernt werden, aber node noch in der Erinnerung existiert.

8voto

lib3d Punkte 2424

Zögern Sie nicht, den Heap zu beobachten, um Speicherlecks in Ereignis-Handlern zu sehen, die einen Verweis auf das Element mit einer Closure und das Element einen Verweis auf den Ereignis-Handler halten.

Garbage Collector mag keine zirkulären Referenzen.

Üblicher Fall eines Speicherlecks: Geben Sie zu, dass ein Objekt einen Verweis auf ein Element hat. Dieses Element hat einen Verweis auf den Handler. Und der Handler hat einen Verweis auf das Objekt. Das Objekt hat Verweise auf viele andere Objekte. Dieses Objekt war Teil einer Sammlung, von der Sie glauben, dass Sie sie weggeworfen haben, indem Sie sie aus Ihrer Sammlung herausgenommen haben. => Das gesamte Objekt und alle seine Verweise bleiben bis zum Verlassen der Seite im Speicher. => Sie müssen sich eine komplette Killing-Methode für Ihre Objektklasse überlegen oder z.B. einem mvc-Framework vertrauen.

Zögern Sie auch nicht, die Baumstruktur in den Chrome-Entwicklungswerkzeugen zu verwenden.

8voto

Lucky Soni Punkte 6636

Ich erweitere nur andere Antworten...

Delegierte Ereignishandler werden beim Entfernen eines Elements nicht entfernt.

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

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

Jetzt prüfen:

$._data(document.body, 'events');

7voto

JaskeyLam Punkte 14171

Betreffend jQuery Die folgenden allgemeinen Methoden entfernen auch andere Konstrukte wie Daten und Ereignis-Handler:

entfernen()

Neben den Elementen selbst werden auch alle gebundenen Ereignisse und jQuery-Daten, die mit den Elementen verbunden sind, entfernt.

leer()

Um Speicherlecks zu vermeiden, entfernt jQuery andere Konstrukte wie Daten und Ereignis-Handler aus den untergeordneten Elementen, bevor die Elemente selbst entfernt werden.

html()

Außerdem entfernt jQuery andere Konstrukte wie Daten und Ereignishandler aus untergeordneten Elementen, bevor diese Elemente durch den neuen Inhalt ersetzt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X