391

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

4

6 回答 6

350

现代浏览器

纯 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())将以完全相同的方式运行(考虑使用exampleremove()编写)。removeChild()

然而,这不是真的;jQuery 库实际上有一个内部方法(未记录,理论上可以随时更改)称为cleanData() (这是这个方法的样子),它会在从 DOM 中删除时自动清理与元素关联的所有数据/事件(通过. remove(),empty()html(""))。


旧版浏览器

较旧的浏览器 - 特别是较旧版本的 IE - 由于事件侦听器保持对它们所附加的元素的引用而存在内存泄漏问题。

如果您想更深入地了解用于修复旧版 IE 版本内存泄漏的原因、模式和解决方案,我完全建议您阅读这篇 MSDN 文章,了解和解决 Internet Explorer 泄漏模式。

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

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

于 2012-09-21T09:43:38.987 回答
24

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

于 2012-09-21T10:11:57.287 回答
8

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

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

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

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

于 2013-04-07T00:03:27.437 回答
8

只是扩展其他答案...

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

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

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

现在检查:

$._data(document.body, 'events');
于 2016-06-08T11:58:26.633 回答
7

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

消除()

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

空的()

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

html()

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

于 2016-03-30T06:39:21.340 回答
2

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

于 2012-09-21T09:43:10.917 回答