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

130

如果我有一个父元素,其中包含具有绑定事件监听器的子元素,那么在清除父元素之前是否需要删除这些事件监听器?(例如,parent.innerHTML ='';)如果从DOM中删除了元素但未解除绑定事件监听器,是否可能会出现内存泄漏问题?

2个回答

112

仅更新此处的信息。我一直在测试各种浏览器,特别是针对 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或更少。然而,如果存在内存泄漏,则内存增加约16000kb。始终先删除事件侦听器会导致较低的内存使用(无泄漏)。

结果:

  • IE6 - 内存泄漏
  • IE7 - 内存泄漏
  • IE8 - 没有内存泄漏
  • IE9 - 内存泄漏(???)
  • IE10 - 内存泄漏(???)
  • IE11 - 没有内存泄漏
  • Edge (20) - 没有内存泄漏
  • Chrome (50) - 没有内存泄漏
  • Firefox (46) - 很难说,不会泄漏太严重,所以可能只是垃圾收集器效率低?最终多出4MB的内存占用原因不明。
  • Opera (36) - 没有内存泄漏
  • Safari (9) - 没有内存泄漏

结论: 最前沿的应用程序可能可以不删除事件侦听器而得到通过。但我仍然认为这是一种良好的实践,尽管有些烦人。


69

简短回答:是的

长一点的回答:大多数浏览器都能正确处理并自行移除这些处理程序。有一些旧浏览器(如果我没记错,包括IE 6和7)会出现问题。是的,可能会出现内存泄漏。你不必担心,但需要注意。请查看这个文档


事实上,尽管大多数现代浏览器不会受到太大影响,但仍然有很多人在使用IE 7。同时,您也可以查看JavaScript中的内存泄漏模式。链接:http://www.ibm.com/developerworks/web/library/wa-memleak/。 - Marcel Korpel
8
有人有足够的知识来更新当前浏览器市场的情况吗?或者这值得另外提一个问题吗?我认为IE7已经被淘汰,而IE8仍然存在。IE8能处理废弃的事件监听器吗? - aidan
57
6年后,我认为IE < 10可以安全地视为废弃,除了访问Yahoo和AOL之外的其他网站上,没有人会使用它。此时仍然无意识地使用IE的人可能更容易成为印度电话诈骗的受害者或感染病毒,而不是遇到事件处理程序减慢浏览器速度等问题。 - Braden Best

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接