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

时间:2012-09-21 09:42:33

标签: javascript jquery dom memory memory-leaks

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

6 个答案:

答案 0 :(得分:261)

现代浏览器

普通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.

还有一些与此相关的文章:

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

答案 1 :(得分:21)

关于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仍然存在于内存中。

答案 2 :(得分:7)

在事件处理程序中保持对带元素的元素引用以及元素保持对事件处理程序的引用时,请不要犹豫,查看堆以查看内存泄漏。

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

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

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

答案 3 :(得分:7)

只是扩展其他答案......

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

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

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

现在检查:

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

答案 4 :(得分:6)

关于Jupyter Console 4.1.1 Jupyter Console 4.1.1 C:\Users\Admin\Anaconda3\python.EXE: Error while finding spec for 'ipykernel.__main__' (<class 'ImportError'>: Module use of python33.dll conflicts with this version of Python.); 'ipykernel' is a package and cannot be directly executed ,以下常用方法还将删除其他构造,如数据和事件处理程序:

remove()

  

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

empty()

  

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

html()

  

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

答案 5 :(得分:2)

是的,垃圾收集器也将删除它们。但是,传统浏览器可能并非总是如此。