如果删除了DOM元素,它的侦听器也会从内存中删除吗?

#1 楼

现代浏览器

普通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中的相关方法(例如remove())将以完全相同的方式起作用(例如考虑remove()是使用removeChild()编写的)。

但是,这不是真的; jQuery库实际上有一个内部方法(未记录,理论上可以随时更改),称为cleanData()(此方法的样子),该方法会自动清除与元素相关的所有数据/事件,并将其从DOM(通过remove()empty()html("")等)。由于事件侦听器保留对其附加元素的引用而导致的泄漏问题。

如果要更深入地解释用于修复旧版IE版本内存泄漏的原因,模式和解决方案,我强烈建议您阅读此MSDN文章,了解和解决Internet Explorer泄漏模式。

更多与此相关的文章:


JScript内存泄漏
IE8中的内存泄漏
JavaScript内存泄漏

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

评论


根据jquery文档,在元素上使用remove()方法时,所有事件侦听器都将从内存中删除。这会影响到它自身的元素和所有子节点。如果要将事件列表保存在内存中,则应改用.detach()。当删除的元素要再次插入dom时很有用。

–Lothre1
2013年5月1日13:57



如果元素包含子元素,是否也会分离子元素上的事件侦听器?

– CBeTJlu4ok
2014年1月25日上午8:04

@ Lothre1-仅在使用remove方法时。大多数情况下,DOM只会被完全擦除。 (例如涡轮链接等)。我想知道如果我做document.body.innerHTML =''...

– vsync
2014年9月17日下午13:17

我需要的不仅仅是“个人经验”,更像是硬数据和测试以及指向规范的链接,这些规范说内存如何在不再存在于文档中的节点上保持持久性,这太重要了,以至于只能凭空证明某人的话:

– vsync
2014-09-18 13:27

@ Lothre1谢谢-我已经更深入地研究了,发现jQuery在这方面与常规JavaScript有何不同。已更新答案。

–dsgriffin
15年2月10日在17:45

#2 楼

关于jQuery:


.remove()方法将元素从
DOM中删除。要删除元素本身以及元素中的所有内容时,请使用.remove()。除了元素本身之外,还删除了所有
绑定的事件以及与该元素关联的jQuery数据。
要删除元素而不删除数据和事件,请改用.detach()



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

.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拾取并删除)。

–奥列格·沃尔科夫(Oleg V. Volkov)
2012年12月6日在8:49

我知道:D。那么,您编辑问题的人在哪里? COS我可能发誓,在前面的问题中,有一些关于使用jquery删除DOM元素的事情。现在,我的回答听起来像是我在解释一些事情,只是在抚摸我的自我。嘿,你总是可以投票

–Sreenath S
2012年12月6日上午10:04

#3 楼

不要犹豫地观看堆,以查看事件处理程序中的内存泄漏,该事件处理程序使用闭包保留对元素的引用,而元素保留对事件处理程序的引用。

通常的内存泄漏情况:
允许对象具有对元素的引用。该元素具有对处理程序的引用。处理程序对对象有一个引用。
对象有对许多其他对象的引用。该对象是您认为已从集合中取消引用而丢弃的集合的一部分。
=>整个对象及其所引用的所有对象都会保留在内存中,直到页面退出为止。
=>考虑为您的对象类提供一种完整的杀死方法,或例如信任mvc框架。

#4 楼

关于jQuery,以下常用方法还将删除其他构造,例如数据和事件处理程序:

remove()


除了元素本身之外,所有与元素关联的绑定事件和jQuery数据被删除。


empty()


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


html()


另外,jQuery在将子元素替换为子元素之前,从子元素中删除了其他构造,例如数据和事件处理程序。新内容。


#5 楼

只是扩展其他答案...

删除元素后,委派的事件处理程序将不会删除。

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM


现在检查:

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


评论


事件处理程序是附加在body上的,而不是附加在#someEl上的,当然,只要body仍在此处,则不应删除该处理程序。

–杨顺泰
17年7月27日在11:19

可以手动将其删除:stackoverflow.com/questions/22400907/…

–方兴
18年1月23日在5:43

#6 楼

是的,垃圾收集器也会将其删除。但是,旧版浏览器可能并非总是如此。

评论


您的声明应得到API文档,示例等的支持。

– Paolo Fulgoni
15年2月26日在9:20