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

use*_*450 65 javascript dom memory-leaks javascript-events

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

Dwi*_*ght 47

只是在这里更新信息.我一直在测试各种浏览器,特别是针对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>
Run Code Online (Sandbox Code Playgroud)

如果没有内存泄漏,运行测试后,使用的内存将增加大约1000kb或更少.但是,如果存在内存泄漏,内存将增加大约16,000kb.首先删除事件侦听器总是会导致内存使用率降低(无泄漏).

结果:

  • IE6 - 内存泄漏
  • IE7 - 内存泄漏
  • IE8 - 没有内存泄漏
  • IE9 - 内存泄漏(???)
  • IE10 - 内存泄漏(???)
  • IE11 - 没有内存泄漏
  • 边缘(20) - 没有内存泄漏
  • Chrome(50) - 没有内存泄漏
  • Firefox(46) - 很难说,不会泄漏严重,所以可能只是低效的垃圾收集器?没有明显原因,额外增加4MB.
  • Opera(36) - 没有内存泄漏
  • Safari(9) - 没有内存泄漏

结论:出血边缘应用程序可能无法移除事件侦听器.但是,尽管烦恼,我仍然认为这是一种很好的做法.


jwu*_*ler 36

简短回答:是的

答案很长:大多数浏览器都能正确处理并自行删除这些处理程序.有些旧的浏览器(IE 6和7,如果我没记错的话)正在弄乱这个.是的,可能存在内存泄漏.你不应该担心这个,但你需要.看看这个文件.

  • 6年后,我认为`IE <10`可以安全地被认为是弃用的,并且此时不会被雅虎和AOL以外的网站使用.任何那些在这一点上非常使用IE的人可能更有可能成为印度手机诈骗的受害者或者获得病毒而不是事件处理程序的问题,无论如何都会减慢他们对浏览器的影响. (11认同)
  • 有人知道足以为当前的浏览器市场更新这个吗?或者这是值得一个单独的问题?IE7我认为[几乎逐步淘汰](http://theie7countdown.com/),而[ie8](http://theie8countdown.com/)仍然在闲逛.IE8是否处理废弃的事件监听器? (6认同)