Czy programy obsługi zdarzeń na węźle DOM są usuwane wraz z węzłem?
(Uwaga: używam jQuery poniżej, ale pytanie jest naprawdę ogólne Javascript jeden.)
Powiedzmy, że mam div#formsection
, którego zawartość jest wielokrotnie aktualizowana za pomocą AJAX, Tak:
var formSection = $('div#formsection');
var newContents = $.get(/* URL for next section */);
formSection.html(newContents);
Za każdym razem, gdy aktualizuję ten div, uruchamiam niestandardowe zdarzenie , które wiąże procedury obsługi zdarzeń z niektórymi nowo dodanymi elementami, takimi jak:
// When the first section of the form is loaded, this runs...
formSection.find('select#phonenumber').change(function(){/* stuff */});
...
// ... when the second section of the form is loaded, this runs...
formSection.find('input#foo').focus(function(){/* stuff */});
Więc: wiążę procedury obsługi zdarzeń z niektórymi węzłami DOM, później usuwam te węzły DOM i wstawiam nowe (html()
robi to) i powiązanie procesów obsługi zdarzeń z nowymi węzłami DOM.
Czy moje procedury obsługi zdarzeń są usuwane wraz z węzłami DOM, z którymi są powiązane? innymi słowy, gdy Ładuję nowe sekcje, czy wiele bezużytecznych programów obsługi zdarzeń gromadzi się w pamięci przeglądarki, czekając na zdarzenia na węzłach DOM, które już nie istnieją, czy też są usuwane po usunięciu ich węzłów DOM?
Pytanie Dodatkowe: Jak można to samemu przetestować?
5 answers
Funkcje obsługi zdarzeń podlegają takiemu samemu zbieraniu śmieci, jak inne zmienne. Oznacza to, że zostaną one usunięte z pamięci, gdy interpreter stwierdzi, że nie ma możliwości uzyskania odniesienia do funkcji. Samo usunięcie węzła nie gwarantuje jednak usuwania śmieci. Na przykład, weźmy ten węzeł i powiązaną obsługę zdarzeń
var node = document.getElementById('test');
node.onclick = function() { alert('hai') };
Teraz pozwala usunąć węzeł z DOM
node.parentNode.removeChild(node);
Więc node
nie będzie już widoczny na Twoim strona internetowa, ale wyraźnie nadal istnieje w pamięci, podobnie jak obsługa zdarzenia
node.onclick(); //alerts hai
Tak długo, jak odniesienie do {[5] } jest nadal dostępne, jego powiązane właściwości (z których onclick
jest jednym) pozostaną nienaruszone.
Teraz spróbujmy bez tworzenia zwisającej zmiennej
document.getElementById('test').onclick = function() { alert('hai'); }
document.getElementById('test').parentNode.removeChild(document.getElementById('test'));
W tym przypadku wydaje się, że nie ma dalszej drogi dostępu do węzła DOM #test, więc gdy uruchomiony jest cykl zbierania śmieci, procedura obsługi onclick
powinna zostać usunięta z pamięć.
onclick
document.getElementById('test').onclick = function() {
var i = 0;
setInterval(function() {
console.log(i++);
}, 1000);
this.parentNode.removeChild(this);
};
Więc po kliknięciu #test, element zostanie natychmiast usunięty, jednak sekundę później, a co sekundę później, zobaczysz zwiększoną liczbę wydrukowaną na konsoli. Węzeł jest usuwany, a dalsze odniesienie do niego nie jest możliwe, jednak wygląda na to, że część z nich pozostała. W tym przypadku sama funkcja obsługi zdarzeń prawdopodobnie nie jest zachowana w pamięci, ale utworzony przez nią zakres.
Więc odpowiedź chyba jest; to zależy. Jeśli istnieją zwisające, dostępne odniesienia do usuniętych węzłów DOM, powiązane z nimi procedury obsługi zdarzeń nadal będą znajdować się w pamięci, wraz z resztą ich właściwości. Nawet jeśli tak nie jest, zakres utworzony przez funkcje obsługi zdarzeń może być nadal używany i w pamięci.
W większości przypadki (i szczęśliwie ignorując IE6) najlepiej po prostu zaufać Garbage Collectorowi, aby wykonał swoją pracę, Javascript nie jest przecież C. Jednak w przypadkach, takich jak w poprzednim przykładzie, ważne jest, aby napisać funkcje destruktora jakiegoś rodzaju, aby pośrednio wyłączyć funkcjonalność.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-02 17:51:39
JQuery dokłada wszelkich starań, aby uniknąć wycieków pamięci podczas usuwania elementów z DOM. Tak długo, jak używasz jQuery do usuwania węzłów DOM, usuwanie programów obsługi zdarzeń i dodatkowych danych powinno być obsługiwane przez jQuery. Gorąco polecam lekturę Johna Resiga sekrety Ninja JavaScript Jak idzie w szczegółach na temat potencjalnych wycieków w różnych przeglądarkach i jak biblioteki JavaScript, takie jak jQuery obejść te problemy. Jeśli nie używasz jQuery, na pewno masz aby martwić się wyciekiem pamięci przez osierocone procedury obsługi zdarzeń podczas usuwania węzłów DOM.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-02 17:56:57
Może być konieczne usunięcie tych procedur obsługi zdarzeń.
Wycieki pamięci Javascript po rozładowaniu strony internetowej
W naszym kodzie, który nie jest oparty na jQuery, ale na jakimś prototypowym dewiancie, mamy inicjalizatory i destruktory w naszych klasach. Stwierdziliśmy, że usuwanie programów obsługi zdarzeń z obiektów DOM jest absolutnie niezbędne, gdy podczas działania niszczymy nie tylko naszą aplikację, ale także poszczególne widżety.
W Przeciwnym Razie skończymy z wyciekami pamięci w IE.
To zaskakująco łatwo uzyskać wycieki pamięci w IE - nawet gdy rozładujemy stronę, musimy być pewni, że aplikacja" zamyka się " czysto, sprzątając wszystko - lub proces IE będzie rosnąć z czasem.
Edit: aby zrobić to poprawnie mamy obserwatora zdarzeń na window
dla zdarzenia unload
. Kiedy to nastąpi, nasz łańcuch destruktorów zostanie wezwany do prawidłowego oczyszczenia każdego obiektu.
I przykładowy kod:
/**
* @constructs
*/
initialize: function () {
// call superclass
MyCompany.Control.prototype.initialize.apply(this, arguments);
this.register(MyCompany.Events.ID_CHANGED, this.onIdChanged);
this.register(MyCompany.Events.FLASHMAPSV_UPDATE, this.onFlashmapSvUpdate);
},
destroy: function () {
if (this.overMap) {
this.overMap.destroy();
}
this.unregister(MyCompany.Events.ID_CHANGED, this.onIdChanged);
this.unregister(MyCompany.Events.FLASHMAPSV_UPDATE, this.onFlashmapSvUpdate);
// call superclass
MyCompany.Control.prototype.destroy.apply(this, arguments);
},
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:01
Niekoniecznie
Dokumentacja metody jQuery empty()
odpowiada na moje pytanie i daje mi rozwiązanie problemu. Pisze:
Aby uniknąć wycieków pamięci, jQuery usuwa inne konstrukcje, takie jak dane i obsługa zdarzeń z elementów potomnych przed usunięciem elementów siebie.
Więc: 1) jeśli nie zrobilibyśmy tego wprost, dostalibyśmy wycieki pamięci, a 2) używając empty()
, mogę tego uniknąć.
Dlatego powinienem zrobić to:
formSection.empty();
formSection.html(newContents);
Wciąż nie jest dla mnie jasne, czy sam by się tym zajął, ale jedna dodatkowa linijka na pewno mi nie przeszkadza.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-02 17:49:32
Chciałem poznać siebie, więc po małym teście, myślę, że odpowiedź brzmi tak.
RemoveEvent jest wywoływany, gdy ty .Usuń () coś z DOM.
Jeśli chcesz zobaczyć go samodzielnie, możesz spróbować tego i postępować zgodnie z kodem, ustawiając punkt przerwania. (Używałem jquery 1.8.1)
Dodaj najpierw nowy div:
$('body').append('<div id="test"></div>')
Sprawdź$.cache
, aby upewnić się, że nie ma żadnych zdarzeń związanych z nim. (powinien to być ostatni obiekt)
Dołącz Zdarzenie kliknięcia do Informatyka:$('#test').on('click',function(e) {console.log("clicked")});
Przetestuj i zobacz nowy obiekt w$.cache
:$('#test').click()
Usuń go, a zobaczysz, że obiekt$.cache
również zniknął:$('#test').remove()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-20 04:45:49