Bir DOM Öğesi kaldırılırsa dinleyicileri de bellekten kaldırılır mı?


Yanıtlar:


307

Modern tarayıcılar

Düz JavaScript

Kaldırılan bir DOM öğesi referans içermiyorsa (ona işaret eden referans yok) evet - öğenin kendisi, çöp toplayıcı ve bununla ilişkili olay işleyicileri / dinleyicileri tarafından alınır.

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.

Ancak; hala söz konusu öğeye işaret eden referanslar varsa, öğe ve olay dinleyicileri bellekte tutulur.

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

JQuery'deki (örneğin remove()) ilgili yöntemlerin aynı şekilde çalışacağını varsaymak adil olacaktır (örneğin, düşünülerek remove()yazılmıştır removeChild()).

Ancak, bu doğru değildir ; JQuery kütüphanesi aslında denilen (ki her an değiştirilebilir ve belgesiz teoride olduğu) bir iç yöntemi vardır cleanData() (burada ne gibi bu yöntem görünüyor olduğunu otomatik olarak DOM çıkarılması üzerine bir öğe ile ilgili tüm verileri / olayları temizler) (aracılığıyla olabilir. remove(), empty(), html("")vb.)


Eski tarayıcılar

Eski tarayıcıların - özellikle IE'nin eski sürümlerinin - olay dinleyicilerinin bağlı oldukları öğelere ilişkin referansları tutmaları nedeniyle bellek sızıntısı sorunları olduğu bilinmektedir.

Eski IE sürümü bellek sızıntılarını gidermek için nedenlerin, desenlerin ve çözümlerin daha ayrıntılı bir açıklamasını istiyorsanız , Internet Explorer Sızıntı Desenlerini Anlama ve Çözme hakkındaki bu MSDN makalesini tamamen okumanızı öneririz .

Bununla ilgili birkaç makale daha:

Dinleyicileri kendiniz manuel olarak kaldırmak, muhtemelen bu durumda girmek için iyi bir alışkanlık olacaktır (yalnızca bellek uygulamanız için çok önemliyse ve aslında bu tarayıcıları hedefliyorsanız).


22
Bir öğe üzerinde remove () yöntemi kullanılırken jquery Documentation'a göre, tüm olay dinleyicileri bellekten kaldırılır. Bu, kendi oluşturduğu öğeyi ve tüm alt düğümleri etkiler. Olay listelerini bellekte tutmak istiyorsanız, bunun yerine .detach () kullanmanız gerekir. Çıkarılan elemanlar dom üzerine tekrar takılacaksa kullanışlıdır.
Lothre1

1
Öğe alt öğeler içeriyorsa, alt öğelerdeki olay listelerini de ayırır mı?
CBeTJlu4ok

1
@ Lothre1 - sadece removeyöntemi kullanırken . çoğu zaman DOM tamamen silinir. (turbo bağlantılar gibi bir şey). Eğer yaparsam hafızanın nasıl etkilendiğini merak ediyorum document.body.innerHTML = ''...
vsync

1
Ben "kişisel deneyim" daha fazla, daha sert veri ve testler ve daha fazla belgedeki düğümlerde bellek nasıl kalıcı olduğunu söyleyen özellikleri bağlantıları gibi daha fazla gerekir, bu sadece kanıt olmadan birinin sözüne güvenmek için çok önemlidir :)
vsync

1
@ Lothre1 Teşekkürler - Ben biraz daha derin kazdık ve jQuery bu açıdan normal JavaScript farklı davranır öğrendim. Cevabı güncellediniz.
dsgriffin

23

jQuery ile ilgili:

.remove () yöntemi, öğeleri DOM'dan çıkarır. Öğenin kendisini ve içindeki her şeyi kaldırmak istediğinizde .remove () öğesini kullanın. Öğelerin kendilerine ek olarak, öğelerle ilişkili tüm ilişkili olaylar ve jQuery verileri kaldırılır. Verileri ve olayları kaldırmadan öğeleri kaldırmak için, bunun yerine .detach () öğesini kullanın.

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

jQuery v1.8.2 .remove()kaynak kodu:

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

görünüşe göre jQuery kullanır node.removeChild()

Buna göre: 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.

yani olay dinleyicileri kaldırılabilir, ancak nodeyine de bellekte bulunur.


3
Sadece karışıklık ekliyorsunuz - jQuery, işleyicilerin bu kadar basit removeChildyapamayacağı hiçbir şey yapmıyor. Her ikisi de size ikinci kez tekrar takmaya devam edebileceğiniz bir referans döndürür (bu durumda açıkça bellekte kalır) veya atış yolu (bu durumda sonunda GC tarafından alınır ve kaldırılır).
Oleg V. Volkov

biliyorum. soruyu düzenleyen siz neredesiniz? çünkü daha önce soruda, bir DOM öğesini kaldırmak için jquery kullanma hakkında bir şey olduğunu yemin edebilirdi. şimdi cevabım kulağa sadece egomu vurmak için bir şeyler açıklıyormuşum gibi geliyor. hey you always downvote
Sreenath S

8

Olay işleyicilerinde kapaklı bir öğeye bir başvuru ve olay işleyicisine bir başvuru tutan öğe için bellek sızıntılarını görmek için yığını izlemekte tereddüt etmeyin.

Çöp toplayıcı dairesel referansları sevmez.

Her zamanki bellek sızıntısı durumu: bir nesnenin bir öğeye ref'si olduğunu kabul edin. Bu elemanın işleyiciye bir referansı vardır. Ve işleyicinin nesneye bir referansı var. Nesnenin birçok başka nesneyi de vardır. Bu nesne, koleksiyonunuzdan referans atarak attığınızı düşündüğünüz bir koleksiyonun parçasıydı. => nesnenin tamamı ve tüm referansları sayfadan çıkana kadar bellekte kalır. => nesne sınıfınız için tam bir öldürme yöntemi düşünmeli veya mvc çerçeveye güvenmelisiniz.

Ayrıca, Chrome geliştirici araçlarının İstinat ağacı bölümünü kullanmaktan çekinmeyin.


8

Diğer cevapları uzatmak ...

Yetki verilen olay işleyicileri, öğe kaldırıldıktan sonra kaldırılmayacak.

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

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

Şimdi kontrol et:

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

9
Olay işleyici, #someEl değil, gövdeye bağlıdır, doğal olarak işleyici, gövde hala burada olduğu sürece kaldırılmamalıdır.
Yangshun Tay

Bu manuel olarak kaldırılabilir: stackoverflow.com/questions/22400907/…
fangxing

7

Bununla ilgili olarak jQuery, aşağıdaki yaygın yöntemler veri ve olay işleyicileri gibi diğer yapıları da kaldıracaktır:

Kaldırmak()

Öğelerin kendilerine ek olarak, öğelerle ilişkili tüm ilişkili olaylar ve jQuery verileri kaldırılır.

boş()

Bellek sızıntılarını önlemek için jQuery, öğeleri ve olay işleyicileri gibi diğer yapıları, öğelerin kendisini kaldırmadan önce alt öğelerden kaldırır.

html ()

Ayrıca, jQuery, bu öğeleri yeni içerikle değiştirmeden önce veri ve olay işleyicileri gibi diğer yapıları alt öğelerden kaldırır.


2

Evet, çöp toplayıcı bunları da kaldıracak. Eski tarayıcılarda her zaman böyle olmayabilir.


7
beyanınız API belgeleri, örnekler vb. tarafından desteklenmelidir.
Paolo Fulgoni
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.