Wenn ein DOM-Element entfernt wird, werden auch seine Zuhörer aus dem Speicher entfernt?
Antworten
Zu viele Anzeigen?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).
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.
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.
Betreffend jQuery
Die folgenden allgemeinen Methoden entfernen auch andere Konstrukte wie Daten und Ereignis-Handler:
Neben den Elementen selbst werden auch alle gebundenen Ereignisse und jQuery-Daten, die mit den Elementen verbunden sind, entfernt.
Um Speicherlecks zu vermeiden, entfernt jQuery andere Konstrukte wie Daten und Ereignis-Handler aus den untergeordneten Elementen, bevor die Elemente selbst entfernt werden.
Außerdem entfernt jQuery andere Konstrukte wie Daten und Ereignishandler aus untergeordneten Elementen, bevor diese Elemente durch den neuen Inhalt ersetzt werden.
- See previous answers
- Weitere Antworten anzeigen