【问题标题】:Do I need to remove event listeners before removing elements?删除元素之前是否需要删除事件侦听器?
【发布时间】:2011-08-27 09:21:35
【问题描述】:

如果我的父元素的子元素绑定了事件侦听器,我是否需要在清除父元素之前删除这些事件侦听器? (即parent.innerHTML = '';)如果事件侦听器未从元素中解除绑定(如果从 DOM 中移除),是否会出现内存泄漏?

【问题讨论】:

    标签: javascript dom memory-leaks dom-events


    【解决方案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 - 没有内存泄漏
    • Edge (20) - 没有内存泄漏
    • Chrome (50) - 没有内存泄漏
    • Firefox (46) - 很难说,不会严重泄漏,所以可能只是效率低下的垃圾收集器?无缘无故地以额外的 4MB 结束。
    • Opera (36) - 没有内存泄漏
    • Safari (9) - 没有内存泄漏

    结论: 不删除事件侦听器可能会导致出血边缘的应用程序侥幸逃脱。但我仍然认为这是一种很好的做法,尽管很烦人。

    【讨论】:

      【解决方案2】:

      简短回答:

      长答案:大多数浏览器都会正确处理此问题并自行删除这些处理程序。有一些旧的浏览器(IE 6 和 7,如果我没记错的话)搞砸了。是的,可能存在内存泄漏。你不应该担心这个,但你需要。看看this document

      【讨论】:

      • 确实:尽管大多数当前的浏览器不会受到太大影响,但 IE 7 仍然普遍使用。也可以看看Memory leak patterns in JavaScript
      • 有足够知识的人来为当前的浏览器市场更新这个吗?或者这值得一个单独的问题吗? IE7 我以为是pretty much phased out,而ie8 还在徘徊。 IE8 是否处理废弃的事件监听器?
      • 6 年后,我认为 IE &lt; 10 可以安全地被认为已弃用,并且此时任何访问雅虎和 AOL 以外的网站的人都不会使用它。无论如何,在这一点上反常使用 IE 的任何人都更有可能成为印度电话诈骗或感染病毒的受害者,而不是事件处理程序减慢浏览器速度的问题。
      猜你喜欢
      • 2020-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-03
      • 2013-06-27
      • 1970-01-01
      • 2018-09-04
      相关资源
      最近更新 更多