DOM要素が削除された場合、そのリスナーもメモリから削除されますか?


回答:


307

最新のブラウザ

プレーンJavaScript

削除されたDOM要素が参照なし(それを指す参照がない)の場合、はい -要素自体は、ガベージコレクターとそれに関連するイベントハンドラー/リスナーによってピックアップされます。

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.

しかしながら; まだその要素を指す参照がある場合、要素とそのイベントリスナーはメモリに保持されます。

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の関連メソッド(などremove())がまったく同じように機能すると想定するのは公平remove()です(removeChild()例として、

ただし、これは正しくありません。jQueryライブラリには、DOMからの削除時に要素に関連付けられたすべてのデータ/イベントを自動的にクリーンアップする内部メソッド(ドキュメント化されておらず、理論的にはいつでも変更できる)が呼び出されますcleanData() (これはこのメソッドの外観です)。 (これは、を介してもremove()empty()html("")など)。


古いブラウザ

古いブラウザ、特にIEの古いバージョンは、イベントリスナーが接続されている要素への参照を保持しているため、メモリリークの問題があることがわかっています。

従来のIEバージョンのメモリリークを修正するために使用された原因、パターン、およびソリューションの詳細な説明が必要な場合は、Internet Explorerのリークパターンの理解と解決に関するこのMSDNの記事をよくお読みください

これに関連するいくつかの記事:

この場合、手動でリスナーを手動で削除することをお勧めします(メモリがアプリケーションに不可欠であり、実際にそのようなブラウザーを対象にしている場合のみ)。


22
jqueryドキュメントによると、要素に対してremove()メソッドを使用すると、すべてのイベントリスナーがメモリから削除されます。これは、それ自体の要素とすべての子ノードに影響します。イベントリスナーをメモリに保持する場合は、代わりに.detach()を使用する必要があります。削除された要素がdomに再度挿入されるときに便利です。
Lothre1 2013年

1
要素に子要素が含まれている場合、子要素のイベントリスナーも切り離されますか?
CBeTJlu4ok 2014年

1
@ Lothre1- removeメソッドを使用する場合のみです。ほとんどの場合、DOMは完全に消去されます。(ターボリンクか何かのように)。私は私がしなければ、メモリがどのように影響されるか疑問に思ってdocument.body.innerHTML = ''...
VSYNC

1
私は「個人的な経験」以上のものを必要とするでしょう。ハードデータやテスト、スペックへのリンクなど、ドキュメントに存在しないノードでメモリがどのように永続するかを示します。これは、証明なしに誰かの言葉を信頼するにはあまりにも重要です:)
vsync

1
@ Lothre1ありがとう-私は少し深く掘り下げて、この点でjQueryが通常のJavaScriptとどのように異なる動作をするかを発見しました。答えを更新しました。
dsgriffin 2015

23

jQueryに関して:

.remove()メソッドは、DOMから要素を取り出します。要素自体だけでなく、要素内のすべてを削除する場合は、.remove()を使用します。要素自体に加えて、要素に関連付けられたすべてのバインドされたイベントとjQueryデータが削除されます。データとイベントを削除せずに要素を削除するには、代わりに.detach()を使用します。

リファレンス:http : //api.jquery.com/remove/

jQuery v1.8.2 .remove()ソースコード:

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は node.removeChild()

これによると: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.

つまり、イベントリスナーは削除される可能性がありますが、nodeそれでもメモリ内に存在します。


3
混乱を加えているだけです。jQueryは、単純なハンドラーではできないことを何もしremoveChildません。どちらも、後者を再アタッチする(この場合は明らかにメモリ内に残る)か、ウェイをスローする(この場合は最終的にGCによってピックアップされて削除される)ために保持できる参照を返します。
Oleg V. Volkov

私は知っている:D。それであなたは質問を編集した人はどこですか?cos私は以前の質問で、jqueryを使用してDOM要素を削除することについて何かがあったと誓ったかもしれません。今、私の答えは、自分のエゴを撫でるためだけに説明しているようなものです。いつでも反対投票できます
Sreenath S

8

ヒープを監視して、クロージャーで要素への参照を保持するイベントハンドラーと、イベントハンドラーへの参照を保持する要素でメモリリークを確認することをためらわないでください。

ガベージコレクターは循環参照を好みません。

通常のメモリリークの場合:オブジェクトに要素への参照があることを認めます。その要素にはハンドラーへの参照があります。そして、ハンドラーはオブジェクトへの参照を持っています。オブジェクトには他の多くのオブジェクトへの参照があります。このオブジェクトは、コレクションから参照解除することで破棄したと考えられるコレクションの一部でした。=>オブジェクト全体とそれが参照するすべてのものは、ページが終了するまでメモリに残ります。=>あなたはあなたのオブジェクトクラスのための完全な殺害方法について考えるか、例えばmvcフレームワークを信頼する必要があります。

さらに、Chrome開発ツールの保持ツリーの部分を使用することをためらわないでください。


8

他の答えを拡張するだけ...

委任されたイベントハンドラーは、要素の削除時に削除されません。

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

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

今チェックしてください:

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

9
イベントハンドラーは#someElではなく本体に接続されます。当然、本体がまだ存在している限り、ハンドラーを削除しないでください。
Yangshun Tay 2017

これは、手動で削除することができます。stackoverflow.com/questions/22400907/...を
fangxing

7

に関してjQuery、次の一般的なメソッドは、データやイベントハンドラなどの他の構成要素も削除します。

削除する()

要素自体に加えて、要素に関連付けられたすべてのバインドされたイベントとjQueryデータが削除されます。

空の()

メモリリークを回避するために、jQueryは、要素自体を削除する前に、データやイベントハンドラーなどの他の構成要素を子要素から削除します。

html()

さらに、jQueryは、データやイベントハンドラーなどの他の構成要素を子要素から削除してから、それらの要素を新しいコンテンツに置き換えます。


2

はい、ガベージコレクターもそれらを削除します。ただし、レガシーブラウザでは常にそうであるとは限りません。


7
あなたの文は、などのAPIドキュメント、例、によってサポートされる必要があります
パオロFulgoni
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.