Javascript 如果 DOM 元素被移除,它的侦听器是否也从内存中移除?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12528049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 10:37:43  来源:igfitidea点击:

If a DOM Element is removed, are its listeners also removed from memory?

javascriptjquerydommemorymemory-leaks

提问by nimrod

If a DOM Element is removed, are its listeners removed from memory too?

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

采纳答案by dsgriffin

Modern browsers

现代浏览器

Plain JavaScript

纯 JavaScript

If a DOM element which is removed is reference-free (no references pointing to it) then yes- the element itself is picked up by the garbage collector as well as any event handlers/listeners associated with it.

如果被移除的 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.

However; if there are references that still point to said element, the element and its event listeners are retained in memory.

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

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

It would be fair to assume that the relevant methods in jQuery (such as remove()) would function in the exact same way (considering remove()was written using removeChild()for example).

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

However, this isn't true; the jQuery library actually has an internal method (which is undocumented and in theory could be changed at any time) called cleanData()(here is what this method looks like) which automatically cleans up all the data/events associated with an element upon removal from the DOM (be this via. remove(), empty(), html("")etc).

然而,事实并非如此。jQuery 库实际上有一个内部方法(它没有记录,理论上可以随时更改)被调用cleanData()(这是这个方法的样子),它会在从 DOM 中删除时自动清理与元素关联的所有数据/事件(通过是这样。remove()empty()html("")等等)。



Older browsers

较旧的浏览器

Older browsers - specifically older versions of IE - are known to have memory leak issues due to event listeners keeping hold of references to the elements they were attached to.

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

If you want a more in-depth explanation of the causes, patterns and solutions used to fix legacy IE version memory leaks, I fully recommend you read this MSDN article on Understanding and Solving Internet Explorer Leak Patterns.

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

A few more articles relevant to this:

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

Manually removing the listeners yourself would probably be a good habit to get into in this case (only if the memory is that vital to your application and you are actually targeting such browsers).

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

回答by Sreenath S

regarding jQuery:

关于jQuery:

the .remove() method takes elements out of the DOM. Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.

.remove() 方法从 DOM 中取出元素。当您想要删除元素本身以及其中的所有内容时,请使用 .remove() 。除了元素本身之外,所有与元素关联的绑定事件和 jQuery 数据都将被删除。要在不删除数据和事件的情况下删除元素,请改用 .detach() 。

Reference: http://api.jquery.com/remove/

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

jQuery v1.8.2 .remove()source code:

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;
}

apparently jQuery uses node.removeChild()

显然 jQuery 使用 node.removeChild()

According to this : https://developer.mozilla.org/en-US/docs/DOM/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.

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.

ie event listeners might get removed, but nodestill exists in memory.

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

回答by lib3d

Don't hesitate to watch heap to see memory leaks in event handlers keeping a reference to the element with a closure and the element keeping a reference to the event handler.

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

Garbage collector do not like circular references.

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

Usual memory leak case: admit an object has a ref to an element. That element has a ref to the handler. And the handler has a ref to the object. The object has refs to a lot of other objects. This object was part of a collection you think you have thrown away by unreferencing it from your collection. => the whole object and all it refers will remain in memory till page exit. => you have to think about a complete killing method for your object class or trust a mvc framework for example.

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

Moreover, don't hesitate to use the Retaining tree part of Chrome dev tools.

此外,不要犹豫,使用 Chrome 开发工具的 Retaining tree 部分。

回答by Lucky Soni

Just extending other answers...

只是扩展其他答案...

Delegated events handlers will not be removed upon element removal.

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

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

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

Now check:

现在检查:

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

回答by Jaskey

Regarding jQuery, the following common methods will also remove other constructs such as data and event handlers:

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

remove()

消除()

In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed.

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

empty()

空的()

To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.

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

html()

html()

Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.

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

回答by Darin Dimitrov

Yes, the garbage collector will remove them as well. Might not always be the case with legacy browsers though.

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