要素を削除する前にイベントリスナーを削除する必要がありますか?


85

イベントリスナーがバインドされている子を持つ親要素がある場合、親をクリアする前にそれらのイベントリスナーを削除する必要がありますか?(つまりparent.innerHTML = '';)要素がDOMから削除された場合に、イベントリスナーが要素からバインド解除されていない場合、メモリリークが発生する可能性がありますか?

回答:


51

短い答え:はい

長い答え:ほとんどのブラウザはこれを正しく処理し、それらのハンドラー自体を削除します。これを台無しにしているいくつかの古いブラウザ(私が正しく思い出せばIE 6と7)があります。はい、メモリリークが発生する可能性があります。これについて心配する必要はありませんが、心配する必要があります。このドキュメントをご覧ください。


確かに、現在のほとんどのブラウザーはそれほど苦しむことはありませんが、IE7は依然として一般的に使用されています。また、見ていたJavaScriptでのメモリリークパターンを
Marcel Korpel

7
現在のブラウザ市場向けにこれを更新するのに十分な知識を持っている人はいますか?それとも別の質問の価値がありますか?IE7はかなり段階的に廃止されたと思いましたが、IE8はまだぶらぶらしています。IE8は放棄されたイベントリスナーを処理しますか?
エイダンマイルズ

30
6年後、IE < 10現時点ではYahooとAOL以外のサイトにアクセスする人は、安全に非推奨と見なされ、使用されないと思います。とにかく、この時点で皮肉なことにIEを使用している人は、イベントハンドラーがブラウザーのカニを遅くする問題よりも、インドの電話詐欺の被害に遭ったり、ウイルスに感染したりする可能性が高くなります。
ブレーデンベスト

71

ここで情報を更新するだけです。私はさまざまなブラウザをテストしてきました。特に、iframeのonloadイベントで循環的に依存するイベントリスナーのメモリリークについてテストしています。

使用されるコード(jsfiddleはメモリテストに干渉するため、独自のサーバーを使用してこれをテストします):

<div>
    <label>
        <input id="eventListenerCheckbox" type="checkbox" /> Clear event listener when removing iframe
    </label>
    <div>
        <button id="startTestButton">Start Test</button>
    </div>
</div>

<div>
    <pre id="console"></pre>
</div>

<script>

    (function() {
        var consoleElement = document.getElementById('console');
        window.log = function(text) {
            consoleElement.innerHTML = consoleElement.innerHTML + '<br>' + text;
        };
    }());

    (function() {
        function attachEvent(element, eventName, callback) {
            if (element.attachEvent)
            {
                element.attachEvent(eventName, callback);
            }
            else
            {
                element[eventName] = callback;
            }
        }

        function detachEvent(element, eventName, callback) {
            if (element.detachEvent)
            {
                element.detachEvent(eventName, callback);
            }
            else
            {
                element[eventName] = null;
            }
        }

        var eventListenerCheckbox = document.getElementById('eventListenerCheckbox');
        var startTestButton = document.getElementById('startTestButton');
        var iframe;
        var generatedOnLoadEvent;

        function createOnLoadFunction(iframe) {
            var obj = {
                increment: 0,
                hugeMemory: new Array(100000).join('0') + (new Date().getTime()),
                circularReference: iframe
            };

            return function() {
                // window.log('iframe onload called');
                obj.increment += 1;
                destroy();
            };
        }

        function create() {
            // window.log('create called');
            iframe = document.createElement('iframe');

            generatedOnLoadEvent = createOnLoadFunction(iframe);
            attachEvent(iframe, 'onload', generatedOnLoadEvent);

            document.body.appendChild(iframe);
        }

        function destroy() {
            // window.log('destroy called');
            if (eventListenerCheckbox.checked)
            {
                detachEvent(iframe, 'onload', generatedOnLoadEvent)
            }

            document.body.removeChild(iframe);
            iframe = null;
            generatedOnLoadEvent = null;
        }

        function startTest() {
            var interval = setInterval(function() {
                create();
            }, 100);

            setTimeout(function() {
                clearInterval(interval);
                window.log('test complete');
            }, 10000);
        }

        attachEvent(startTestButton, 'onclick', startTest);
    }());

</script>

メモリリークがない場合、テストの実行後、使用されるメモリは約1000kb以下増加します。ただし、メモリリークが発生すると、メモリは約16,000kb増加します。最初にイベントリスナーを削除すると、常にメモリ使用量が少なくなります(リークはありません)。

結果:

  • IE6-メモリリーク
  • IE7-メモリリーク
  • IE8-メモリリークなし
  • IE9-メモリリーク(???)
  • IE10-メモリリーク(???)
  • IE11-メモリリークなし
  • エッジ(20)-メモリリークなし
  • Chrome(50)-メモリリークなし
  • Firefox(46)-言うのは難しいですが、ひどく漏れないので、おそらく非効率的なガベージコレクターですか?明らかな理由もなく、追加の4MBで終了します。
  • Opera(36)-メモリリークなし
  • Safari(9)-メモリリークなし

結論:最先端のアプリケーションは、イベントリスナーを削除しないことでおそらく回避できます。しかし、煩わしさにもかかわらず、それでも良い習慣だと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.