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

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

121177 次浏览

是的,垃圾收集器也会删除它们。不过,传统浏览器可能并不总是这样。

现代浏览器

纯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() (下面是这个方法的样子),它在从DOM中移除时自动清理与元素相关的所有数据/事件。remove()empty()html("")等)。


老版本浏览器

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

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

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

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

关于jQuery:

的.remove()方法将元素从 DOM。当您想删除元素本身时,也可以使用.remove() 就像里面的一切一样。除了元素本身,所有 绑定事件和与元素关联的jQuery数据被移除。 要删除元素而不删除数据和事件,请使用.detach() 相反。< / p >

参考: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.

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

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

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

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

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

对于jQuery,以下常用方法也将删除其他结构,如数据和事件处理程序:

remove()

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

empty()

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

< a href = " http://api.jquery.com/html/ " rel = " noreferrer > html () < / >

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

只是扩展其他答案……

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

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


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

现在检查:

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