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


当前回答

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

其他回答

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

现代浏览器

纯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版本内存泄漏的原因、模式和解决方案,我强烈建议您阅读MSDN关于理解和解决Internet Explorer泄漏模式的文章。

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

JScript内存泄漏 IE8内存泄漏 JavaScript内存泄漏

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

只是扩展其他答案……

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

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

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

现在检查:

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

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

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

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

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

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

remove ()

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

空()

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

html ()

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