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

Javascript 在删除元素之前是否需要删除事件侦听器?,javascript,dom,memory-leaks,dom-events,Javascript,Dom,Memory Leaks,Dom Events,如果父元素的子元素绑定了事件侦听器,那么在清除父元素之前是否需要删除这些事件侦听器?(即,parent.innerHTML='';)如果从DOM中删除某个元素,而该元素未解除事件侦听器的绑定,是否会发生内存泄漏?简短回答:yes 详细回答:大多数浏览器都正确地处理了这个问题,并且自己删除了这些处理程序。有一些较旧的浏览器(如果我没记错的话,就是6和7)把这一切都搞砸了。是的,可能有内存泄漏。你不必为此担心,但你需要。请查看。仅更新此处的信息。我一直在测试各种浏览器,特别是iframe onloa

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

简短回答:yes


详细回答:大多数浏览器都正确地处理了这个问题,并且自己删除了这些处理程序。有一些较旧的浏览器(如果我没记错的话,就是6和7)把这一切都搞砸了。是的,可能有内存泄漏。你不必为此担心,但你需要。请查看。

仅更新此处的信息。我一直在测试各种浏览器,特别是iframe onload事件上循环相关事件侦听器的内存泄漏

使用的代码(JSFIDLE会干扰内存测试,因此请使用您自己的服务器来测试):


删除iframe时清除事件侦听器
启动测试
(功能(){
var consoleElement=document.getElementById('console');
window.log=函数(文本){
consoleElement.innerHTML=consoleElement.innerHTML+'
'+文本; }; }()); (功能(){ 函数attachEvent(元素、事件名、回调){ if(元素附件) { 元素attachEvent(eventName,回调); } 其他的 { 元素[eventName]=回调; } } 函数detachEvent(元素、事件名、回调){ if(element.detachEvent) { detachEvent(eventName,回调); } 其他的 { 元素[eventName]=null; } } var eventListenerCheckbox=document.getElementById('eventListenerCheckbox'); var startTestButton=document.getElementById('startTestButton'); var-iframe; 风险值生成的非风险事件; 函数createOnLoadFunction(iframe){ var obj={ 增量:0, hugeMemory:新数组(100000).join('0')+(new Date().getTime()), 循环引用:iframe }; 返回函数(){ //log('iframe onload called'); 对象增量+=1; 破坏(); }; } 函数create(){ //log('create called'); iframe=document.createElement('iframe'); generatedOnLoadEvent=createOnLoadFunction(iframe); attachEvent(如果框架为“onload”,生成OnLoadEvent); document.body.appendChild(iframe); } 函数销毁(){ //log('destroy called'); 如果(eventListenerCheckbox.checked) { detachEvent(iframe,“onload”,generatedOnLoadEvent) } document.body.removeChild(iframe); iframe=null; generatedOnLoadEvent=null; } 函数startTest(){ var interval=setInterval(函数(){ 创建(); }, 100); setTimeout(函数(){ 间隔时间; window.log(“测试完成”); }, 10000); } 附件(开始按钮,'onclick',开始按钮); }());
如果没有内存泄漏,则在运行测试后,使用的内存将增加约1000kb或更少。但是,如果内存泄漏,内存将增加约16000KB。首先删除事件侦听器通常会降低内存使用率(无泄漏)

结果:

  • IE6-内存泄漏
  • IE7-内存泄漏
  • IE8-无内存泄漏
  • IE9-内存泄漏(???)
  • IE10-内存泄漏(???)
  • IE11-无内存泄漏
  • 边缘(20)-无内存泄漏
  • Chrome(50)-无内存泄漏
  • Firefox(46)-很难说,不会严重泄漏,所以可能只是低效的垃圾收集器?在没有明显原因的情况下,使用额外4MB完成
  • Opera(36)-无内存泄漏
  • Safari(9)-无内存泄漏
结论:
前沿应用程序可能不需要删除事件侦听器。但我还是认为这是一个很好的做法,尽管恼人。

确实:虽然大多数当前浏览器不会遭受太多的影响,但IE 7仍然是常用的。另外,看看。是否有人有足够的知识来为当前的浏览器市场更新这个?或者这值得一个单独的问题吗?IE7我以为是的,但现在还在附近。IE8是否处理废弃的事件侦听器?6年后,我认为
IE<10
可以安全地被认为是不推荐使用的,在这一点上,除了Yahoo和AOL之外,任何人都不会使用它。不管怎么说,任何在这一点上使用IE的人都更有可能成为印度电话诈骗的受害者或感染病毒,而不是遇到事件处理程序减慢浏览器速度的问题。
<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>