在删除元素之前,我是否需要删除事件监听器?


84

如果我有一个父元素,并且子元素绑定了事件侦听器,那么在清除父对象之前,是否需要删除这些事件侦听器?(即parent.innerHTML = '';)如果事件监听器没有从DOM中取消绑定(如果已从DOM中删除),是否会发生内存泄漏?

Answers:


51

简短答案:

长答案:大多数浏览器都能正确处理此问题,并自行删除这些处理程序。有一些较旧的浏览器(IE 6和7,如果我没记错的话)会弄乱这一点。是的,可能存在内存泄漏。您不必为此担心,但是您需要这样做。看一下这个文件


确实:尽管当前大多数浏览器受的影响不那么大,但IE 7仍是常用的。也可以看看JavaScript中的内存泄漏模式
Marcel Korpel

7
是否有足够的知识来为当前的浏览器市场进行更新?还是值得单独提出一个问题?我认为IE7已被逐步淘汰,而ie8仍在徘徊。IE8是否处理废弃的事件侦听器?
艾丹·迈尔斯

27
6年后,我认为IE < 10可以安全地视为已弃用,并且目前不访问Yahoo和AOL以外的网站的任何人都不会使用它。无论如何,任何讽刺地使用IE的人可能比事件处理程序减慢浏览器速度的问题更容易成为印度电话骗局或感染病毒的受害者。
Braden Best,

67

只是在这里更新信息。我一直在测试各种浏览器,特别是针对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)-没有内存泄漏

结论:不删除事件侦听器可能会使流血的边缘应用程序摆脱困境。尽管有烦恼,但我仍然认为这是一种很好的做法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.