【问题标题】:If a DOM Element is removed, are its listeners also removed from memory?如果移除了一个 DOM 元素,它的监听器是否也会从内存中移除?
【发布时间】:2012-09-13 17:30:58
【问题描述】:

如果一个 DOM 元素被移除,它的监听器是否也会从内存中移除?

【问题讨论】:

    标签: javascript jquery dom memory memory-leaks


    【解决方案1】:

    只是扩展其他答案...

    删除元素时不会删除委托事件处理程序。

    $('body').on('click', '#someEl', function (event){
      console.log(event);
    });
    
    $('#someEL').remove(); // removing the element from DOM
    

    现在检查:

    $._data(document.body, 'events');
    

    【讨论】:

    【解决方案2】:

    关于jQuery,以下常用方法也会移除数据和事件处理程序等其他构造:

    remove()

    除了元素本身,所有与元素关联的绑定事件和 jQuery 数据都将被移除。

    empty()

    为避免内存泄漏,jQuery 在删除元素本身之前从子元素中删除其他构造,例如数据和事件处理程序。

    html()

    此外,jQuery 会在用新内容替换这些元素之前从子元素中删除其他结构,例如数据和事件处理程序。

    【讨论】:

      【解决方案3】:

      现代浏览器

      纯 JavaScript

      如果被移除的 DOM 元素是无引用的(没有指向它的引用),那么 - 元素本身被垃圾收集器以及任何相关的事件处理程序/侦听器拾取用它。

      var a = document.createElement('div');
      var b = document.createElement('p');
      // Add event listeners to b etc...
      a.appendChild(b);
      a.removeChild(b);
      b = null; 
      // A reference to 'b' no longer exists 
      // Therefore the element and any event listeners attached to it are removed.
      

      但是;如果有仍然指向该元素的引用,则该元素及其事件侦听器将保留在内存中。

      var a = document.createElement('div');
      var b = document.createElement('p'); 
      // Add event listeners to b etc...
      a.appendChild(b);
      a.removeChild(b); 
      // A reference to 'b' still exists 
      // Therefore the element and any associated event listeners are still retained.
      

      jQuery

      可以公平地假设 jQuery 中的相关方法(例如 remove())将以完全相同的方式运行(例如,考虑到 remove() 是使用 removeChild() 编写的)。

      但是,这不是真的; jQuery 库实际上有一个名为 cleanData() (here is what this method looks like 的内部方法(未记录,理论上可以随时更改),它会在从 DOM 中删除时自动清理与元素关联的所有数据/事件(被此通过。remove()empty()html("") 等)。


      旧版浏览器

      旧版浏览器——尤其是旧版 IE——已知存在内存泄漏问题,因为事件侦听器保留了对它们所附加的元素的引用。

      如果您想更深入地了解用于修复旧版 IE 版本内存泄漏的原因、模式和解决方案,我完全建议您阅读this MSDN article on Understanding and Solving Internet Explorer Leak Patterns.

      还有几篇与此相关的文章:

      在这种情况下,自己手动删除侦听器可能是一个好习惯(仅当内存对您的应用程序至关重要并且您实际上是针对此类浏览器时)。

      【讨论】:

      • 根据 jquery 文档,当在元素上使用 remove() 方法时,所有事件侦听器都会从内存中删除。这会影响它 selft 的元素和所有子节点。如果您想将事件侦听器保留在内存中,您应该使用 .detach() 代替。当要在 dom 上再次插入已删除的元素时很有用。
      • 如果元素包含子元素,它是否也会分离子元素上的事件监听器?
      • @Lothre1 - 仅在使用 remove 方法时。大多数时候 DOM 会被完全擦除。 (如涡轮链接或其他东西)。我想知道如果我这样做document.body.innerHTML = '' ... 会如何影响内存
      • 我需要的不仅仅是“个人经验”,更像是硬数据和测试以及指向规范的链接,这些规范说明内存如何在不再存在于文档中的节点上保持持久性,这太重要了在没有证据的情况下相信某人的话:)
      • @Lothre1 谢谢 - 我已经深入挖掘并发现了 jQuery 在这方面与常规 JavaScript 的行为方式有何不同。已更新答案。
      【解决方案4】:

      不要犹豫,观察堆以查看事件处理程序中的内存泄漏,该事件处理程序保持对带有闭包的元素的引用,并且元素保持对事件处理程序的引用。

      垃圾收集器不喜欢循环引用。

      常见的内存泄漏情况: 承认一个对象有一个元素的引用。该元素具有对处理程序的引用。并且处理程序有一个对象的引用。 该对象具有对许多其他对象的引用。此对象是您认为已通过从您的集合中取消引用它而丢弃的集合的一部分。 => 整个对象及其引用的所有内容都将保留在内存中,直到页面退出。 => 你必须为你的对象类考虑一个完整的杀死方法,或者信任一个 mvc 框架。

      此外,不要犹豫使用 Chrome 开发工具的保留树部分。

      【讨论】:

        【解决方案5】:

        关于 jQuery:

        .remove() 方法将元素从 DOM。 .remove() 当你想删除元素本身时,也可以使用 作为里面的一切。除了元素本身,所有 与元素关联的绑定事件和 jQuery 数据被删除。 要删除元素而不删除数据和事件,请使用 .detach() 而是。

        参考:http://api.jquery.com/remove/

        jQuery v1.8.2.remove()源码:

        remove: function( selector, keepData ) {
            var elem,
                i = 0;
        
            for ( ; (elem = this[i]) != null; i++ ) {
                if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
                    if ( !keepData && elem.nodeType === 1 ) {
                        jQuery.cleanData( elem.getElementsByTagName("*") );
                        jQuery.cleanData( [ elem ] );
                    }
        
                    if ( elem.parentNode ) {
                        elem.parentNode.removeChild( elem );
                    }
                }
            }
        
            return this;
        }
        

        显然 jQuery 使用 node.removeChild()

        据此:https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild

        The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

        即事件监听器可能会被删除,但node 仍然存在于内存中。

        【讨论】:

        • 你只是在增加混乱 - jQuery 对简单的 removeChild 不会做的处理程序没有任何作用。两者还返回一个引用,您可以保留以重新附加后者(在这种情况下它显然保留在内存中)或抛出方式(在这种情况下它最终被 GC 拾取并删除)。
        • 我知道:D。那么您编辑问题的人在哪里?因为我可以发誓在之前的问题中使用 jquery 来删除 DOM 元素是有道理的。现在我的回答听起来像是我在解释事情只是为了抚摸我的自我。嘿,你总是可以投反对票
        【解决方案6】:

        是的,垃圾收集器也会删除它们。不过,旧版浏览器可能并非总是如此。

        【讨论】:

        • 你的说法应该有API文档、例子等支持
        猜你喜欢
        • 2013-09-29
        • 2021-11-21
        • 1970-01-01
        • 1970-01-01
        • 2010-11-11
        • 2021-05-24
        相关资源
        最近更新 更多