Se un elemento DOM viene rimosso, anche i suoi listener vengono rimossi dalla memoria?

Se un elemento DOM viene rimosso, anche i suoi listener vengono rimossi dalla memoria?

Browser moderni

Semplice JavaScript

Se un elemento DOM che viene rimosso è privo di riferimenti (senza riferimenti che puntano ad esso) allora – l’elemento stesso viene raccolto dal garbage collector e da eventuali gestori di eventi / listener associati ad esso.

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. 

Però; se ci sono riferimenti che puntano ancora a detto elemento, l’elemento e i suoi listener di eventi vengono mantenuti in 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

Sarebbe giusto presumere che i metodi rilevanti in jQuery (come remove() ) funzionino nello stesso modo (considerando che remove() stato scritto usando removeChild() per esempio).

Tuttavia, questo non è vero ; la libreria jQuery ha in realtà un metodo interno (che non è documentato e in teoria può essere modificato in qualsiasi momento) chiamato cleanData() (ecco come appare questo metodo ) che pulisce automaticamente tutti i dati / eventi associati a un elemento al momento della rimozione dal DOM (essere questo via. remove() , empty() , html("") ecc.).


Browser meno recenti

I browser più vecchi, in particolare le versioni precedenti di IE, sono noti per avere problemi di perdita di memoria dovuti agli ascoltatori di eventi che mantengono i riferimenti agli elementi a cui erano collegati.

Se si desidera una spiegazione più approfondita delle cause, dei modelli e delle soluzioni utilizzate per correggere le perdite di memoria legacy di IE, vi consiglio caldamente di leggere questo articolo di MSDN su Capire e risolvere i modelli di perdita di Internet Explorer.

Alcuni altri articoli rilevanti per questo:

  • Perdite di memoria JScript
  • Perdite di memoria in IE8
  • Perdite di memoria JavaScript

Rimuovere manualmente gli ascoltatori da solo sarebbe probabilmente una buona abitudine entrare in questo caso (solo se la memoria è così vitale per la tua applicazione e in effetti stai bersagliando tali browser).

per quanto riguarda jQuery:

il metodo .remove () prende elementi dal DOM. Usa .remove () quando vuoi rimuovere l’elemento stesso e tutto ciò che contiene. Oltre agli elementi stessi, vengono rimossi tutti gli eventi associati e i dati jQuery associati agli elementi. Per rimuovere gli elementi senza rimuovere dati ed eventi, usare invece .detach ().

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

jQuery v1.8.2 .remove() codice sorgente:

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

apparentemente jQuery usa node.removeChild()

In base a questo: 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.

cioè i listener di eventi potrebbero essere rimossi, ma il node esiste ancora in memoria.

Non esitare a guardare heap per vedere perdite di memoria nei gestori di eventi mantenendo un riferimento all’elemento con una chiusura e l’elemento che mantiene un riferimento al gestore di eventi.

Ai collezionisti di rifiuti non piacciono i riferimenti circolari.

Caso di perdita di memoria usuale: ammette che un object ha un riferimento a un elemento. Questo elemento ha un riferimento al conduttore. E il conduttore ha un riferimento all’object. L’object ha riferimenti a molti altri oggetti. Questo object faceva parte di una collezione che ritieni di aver gettato via non rispettando la tua collezione. => l’intero object e tutto ciò che rimarrà rimarrà in memoria fino all’uscita dalla pagina. => devi pensare a un metodo completo di uccisione per la tua class object o fidarti di un framework mvc, per esempio.

Inoltre, non esitare a utilizzare la parte Albero di contenimento degli strumenti di sviluppo di Chrome.

Estendendo altre risposte …

I gestori di eventi delegati non verranno rimossi dopo la rimozione degli elementi.

 $('body').on('click', '#someEl', function (event){ console.log(event); }); $('#someEL').remove(); // removing the element from DOM 

Ora controlla:

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

Per quanto riguarda jQuery , i seguenti metodi comuni rimuoveranno anche altri costrutti come i dati e i gestori di eventi:

rimuovere()

Oltre agli elementi stessi, vengono rimossi tutti gli eventi associati e i dati jQuery associati agli elementi.

vuoto()

Per evitare perdite di memoria, jQuery rimuove altri costrutti come dati e gestori di eventi dagli elementi figlio prima di rimuovere gli elementi stessi.

html ()

Inoltre, jQuery rimuove altri costrutti come dati e gestori di eventi da elementi figlio prima di sostituire tali elementi con il nuovo contenuto.

Sì, il garbage collector rimuoverà anche loro. Potrebbe non essere sempre il caso con i browser legacy.