Odpowiedzi:
Zwykły JavaScript
Jeśli usunięty element DOM jest pozbawiony referencji (brak referencji do niego wskazujących), to tak - sam element jest odbierany przez moduł wyrzucający elementy bezużyteczne, a także powiązane z nim procedury obsługi / nasłuchiwania zdarzeń.
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.
Jednak; jeśli istnieją odniesienia, które nadal wskazują na ten element, element i detektory zdarzeń są zachowywane w pamięci.
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
Można byłoby założyć, że odpowiednie metody w jQuery (takie jak remove()
) działałyby dokładnie w ten sam sposób (biorąc pod uwagę, że remove()
zostały napisane przy użyciu removeChild()
np.).
To jednak nie jest prawda ; biblioteka jQuery faktycznie ma wewnętrzną metodę (która jest nieudokumentowana i teoretycznie może być zmieniona w dowolnym momencie) o nazwie cleanData()
(oto jak ta metoda wygląda ), która automatycznie usuwa wszystkie dane / zdarzenia związane z elementem po usunięciu z DOM (czy to przez. remove()
, empty()
, html("")
itp).
W starszych przeglądarkach - szczególnie w starszych wersjach IE - występują problemy z wyciekiem pamięci, ponieważ detektory zdarzeń przechowują odniesienia do elementów, do których zostały dołączone.
Jeśli chcesz bardziej dogłębnego wyjaśnienia przyczyn, wzorców i rozwiązań zastosowanych w celu usunięcia wycieków pamięci starszej wersji IE, w pełni zalecam przeczytanie tego artykułu MSDN na temat zrozumienia i rozwiązywania wzorców wycieków w programie Internet Explorer.
Kilka innych artykułów na ten temat:
Ręczne usuwanie słuchaczy prawdopodobnie byłoby dobrym nawykiem, aby się w tym przypadku przyzwyczaić (tylko jeśli pamięć jest tak ważna dla twojej aplikacji i faktycznie atakujesz takie przeglądarki).
remove
metody. przez większość czasu DOM jest po prostu całkowicie usuwany. (jak linki turbo lub coś takiego). Zastanawiam się, jak wpłynie to na pamięć, jeśli to zrobię document.body.innerHTML = ''
...
w odniesieniu do jQuery:
metoda .remove () usuwa elementy z DOM. Użyj .remove (), jeśli chcesz usunąć sam element, a także wszystko, co się w nim znajduje. Oprócz samych elementów usuwane są wszystkie powiązane zdarzenia i dane jQuery powiązane z elementami. Aby usunąć elementy bez usuwania danych i zdarzeń, użyj zamiast tego metody .detach ().
Odniesienie: http://api.jquery.com/remove/
.remove()
Kod źródłowy jQuery v1.8.2 :
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;
}
najwyraźniej używa jQuery node.removeChild()
Zgodnie z tym: 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.
tzn. detektory zdarzeń mogą zostać usunięte, ale node
nadal istnieją w pamięci.
removeChild
co nie byłoby tak proste w przypadku programów obsługi . Oba również zwracają ci odniesienie, które możesz zachować, aby ponownie dołączyć (w takim przypadku oczywiście pozostaje w pamięci) lub rzucić drogę (w którym to przypadku jest on ostatecznie odbierany przez GC i usuwany).
Nie wahaj się obserwować sterty, aby zobaczyć wycieki pamięci w procedurach obsługi zdarzeń przechowujących odwołanie do elementu z zamknięciem oraz elementu przechowującego odwołanie do procedury obsługi zdarzeń.
Śmieciarka nie lubi okrągłych odniesień.
Przypadek przecieku pamięci: przyznaj, że obiekt ma odwołanie do elementu. Ten element ma odniesienie do modułu obsługi. I handler ma odwołanie do obiektu. Obiekt odnosi się do wielu innych obiektów. Ten obiekt był częścią kolekcji, którą Twoim zdaniem wyrzuciłeś, odwołując ją do swojej kolekcji. => cały obiekt i wszystko, do czego się odnosi, pozostanie w pamięci aż do wyjścia ze strony. => musisz pomyśleć o kompletnej metodzie zabijania dla swojej klasy obiektów lub zaufać np. ramce mvc.
Ponadto nie wahaj się skorzystać z części Drzewo zatrzymujące narzędzi programistycznych Chrome.
Po prostu rozszerzam inne odpowiedzi ...
Programy obsługi zdarzeń delegowanych nie zostaną usunięte po usunięciu elementu.
$('body').on('click', '#someEl', function (event){
console.log(event);
});
$('#someEL').remove(); // removing the element from DOM
Teraz sprawdź:
$._data(document.body, 'events');
W związku z jQuery
tym następujące typowe metody usuwają również inne konstrukcje, takie jak procedury obsługi danych i zdarzeń:
Oprócz samych elementów usuwane są wszystkie powiązane zdarzenia i dane jQuery powiązane z elementami.
Aby uniknąć wycieków pamięci, jQuery usuwa inne konstrukcje, takie jak procedury obsługi danych i zdarzeń z elementów potomnych przed usunięciem samych elementów.
Ponadto jQuery usuwa inne konstrukcje, takie jak procedury obsługi danych i zdarzeń z elementów potomnych przed zamianą tych elementów na nową treść.
Tak, śmieciarz również je usunie. Jednak nie zawsze tak jest w przypadku starszych przeglądarek.