DOM要素が削除された場合、そのリスナーもメモリから削除されますか?
6 に答える
最新のブラウザ
プレーン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ライブラリには、実際には(文書化されておらず、理論的にはいつでも変更できる)内部メソッド(cleanData()
このメソッドは次のようになります)があり、DOMから削除すると要素に関連付けられたすべてのデータ/イベントが自動的にクリーンアップされます。 (これはremove()
、、などを介して)。empty()
html("")
古いブラウザ
古いブラウザ(特に古いバージョンのIE)では、イベントリスナーが接続されている要素への参照を保持しているため、メモリリークの問題が発生することが知られています。
従来のIEバージョンのメモリリークを修正するために使用される原因、パターン、および解決策のより詳細な説明が必要な場合は、 InternetExplorerのリークパターンの理解と解決に関するこのMSDNの記事を読むことを強くお勧めします。
これに関連するいくつかの記事:
この場合、リスナーを手動で削除することをお勧めします(メモリがアプリケーションにとって非常に重要であり、実際にそのようなブラウザーをターゲットにしている場合のみ)。
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
が、メモリにはまだ存在します。
ヒープを監視して、クロージャ付きの要素への参照を保持しているイベントハンドラと、イベントハンドラへの参照を保持している要素のメモリリークを確認することを躊躇しないでください。
ガベージコレクターは循環参照が好きではありません。
通常のメモリリークの場合:オブジェクトが要素への参照を持っていることを認めます。その要素にはハンドラーへの参照があります。そして、ハンドラーはオブジェクトへの参照を持っています。オブジェクトには、他の多くのオブジェクトへの参照があります。このオブジェクトは、コレクションから参照を解除することで破棄したと思われるコレクションの一部でした。=>オブジェクト全体とそれが参照するすべてのものは、ページが終了するまでメモリに残ります。=>オブジェクトクラスの完全なkillingメソッドについて考えるか、たとえばMVCフレームワークを信頼する必要があります。
さらに、Chrome開発ツールの保持ツリー部分を使用することを躊躇しないでください。
他の答えを拡張するだけです...
委任されたイベントハンドラーは、要素の削除時に削除されません。
$('body').on('click', '#someEl', function (event){
console.log(event);
});
$('#someEL').remove(); // removing the element from DOM
ここで確認してください:
$._data(document.body, 'events');
はい、ガベージコレクターもそれらを削除します。ただし、レガシーブラウザでは常にそうであるとは限りません。