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

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

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

ベストアンサー1

ここで情報を更新します。私はさまざまなブラウザをテストしてきましたが、具体的には、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) - はっきりとは言えませんが、リークはひどくないので、単にガベージ コレクターが非効率的であるだけかもしれません。明らかな理由もなく、4 MB 余分に残ります。
  • Opera (36) - メモリリークなし
  • Safari (9) - メモリリークなし

結論: 最先端のアプリケーションでは、イベント リスナーを削除しなくても問題ない可能性があります。ただし、煩わしさはあるものの、それでも良い方法だと私は考えています。

おすすめ記事