我的应用程序中没有遇到内存泄漏,但我担心将来可能出现的问题。我想知道是否做了这样的事情:
SomeClass.prototype.someMethod= function() {
var that= this
this.$div2.click(function() {
that.someMethod2();
});
}
让我们说这个。$ div2附加到另一个div。$ div1。如果我打电话
this.$div1.remove();
后来失去了我的SomeClass实例的引用SomeClass实例是否被垃圾收集?那个HTML元素呢。$ div2?这个。$ div2不会在DOM里面,因为它会附加到这个。$ div1。
我问这个因为。$ div2中的事件处理程序可能会保留对HTML元素的引用。$ div2并且还通过闭包保持对SomeClass实例的引用,因为变量"" 34。
那么我应该关心如何正确删除所有事件和HTML元素吗?或者只是删除" root" element(this。$ div1)解决了这个问题?
答案 0 :(得分:15)
this.$div2
附加到this.$div1
。如果我调用this.$div1.remove();
后来丢失了SomeClass
实例的引用,那么SomeClass
实例会被垃圾回收吗?
是的,当所有对它的引用都丢失了 - 也就是那些通过事件处理程序的引用 - 实例可以被垃圾收集。
HTML元素
this.$div2
怎么样?this.$div2
不会在DOM中,因为它会附加到this.$div1
。
它是否当前附加到DOM无关紧要。如果某些不可收集的对象引用$div1
,它也可以访问其子节点$div2
和那个事件处理程序,因此从处理程序引用的实例将无法收集。
我问这个是因为
this.$div2
中的事件处理程序可能会保留对HTML元素this.$div2
的引用,并且由于变量而通过闭包保留对SomeClass
实例的引用“那个”。
这是一个循环引用, 应该由引擎很好地处理(当圈内的任何对象都没有从外部引用时,它可以被收集)。但是,(旧的?)Internet探测器在圆圈中涉及DOM对象时无法执行此操作。
出于这个原因,.remove
jQuery method(code)在内部调用(internal) cleanData
method,它将所有事件侦听器分离。
那么我应该关心如何正确删除所有事件和HTML元素吗?或者只是删除“root”元素(这个。$ div1)解决了这个问题?
是的,在jQuery包装器上调用remove
会自动删除所有事件(来自所有子元素)和DOM节点。
答案 1 :(得分:7)
我是否应该关心正确删除所有事件和HTML元素 像这样?
简短的回答是不!至少在99%的情况下,它无论以何种方式都无关紧要,因为与网页使用的整体内存相比,一个DOM元素使用的内存是微不足道的。
然而,释放通过处置不需要的对象所使用的内存总是一个好习惯,但是你不能说GC肯定会释放元素使用的内存,因为垃圾收集完全取决于浏览器!理论上GC只应在没有对DOM元素的引用时启动,至少是Chrome works的引用,但在JavaScript这样的语言中,你没有明确告诉你完成对象的运行时间在JavaScript中,事情变得如此迅速:函数可能会将对象传递给更多的函数,对象可能会作为另一个对象中的成员被保存,对象可能会通过闭包等引用,所以它完全取决于浏览器如何以及收集什么!
在你的情况下删除div1
释放html文档并且元素不会在视图中呈现,实际上jQuery的remove
方法负责删除附加的所有事件,expando属性和子元素与元素本身一起使用元素,但是在另一个对象中保留div1
和div2
的引用,使两个DOM元素成为孤立元素!删除SomeClass
实例变量会释放对DOM元素的所有引用,使它们成为垃圾收集的候选者,但是这里有一个棘手的that
变量,它导致DOM元素通过SomeClass
实例引用clusure!此问题在IE中称为Circular Reference
:
存储对一个引用的JavaScript对象和DOM元素 另一个原因导致Internet Explorer的垃圾收集器无法回收 内存,导致内存泄漏
You can read more about it here
这个特定的泄漏主要是历史感兴趣IE< 8,但打破循环链接的一个很好的例子是避免使用变量that
,而是使用proxy或delegate来改变事件处理程序对某些特定上下文的上下文。
ECMA 5th bind method退出了有用的更改上下文,这里是一个基于代码的简单处理程序,而不使用变量闭包:
this.$div2.click((function() {
this.someMethod2();
}).bind(this));
答案 2 :(得分:1)
如果要动态创建元素,则为其分配事件。我认为你的代码不是一个很好的方法。你应该遵循这样的方式:
对于固定元素,如果需要事件,请使用这两个函数;第一个在构造函数中调用,第二个在析构函数中调用。
on_Events: function() {
$('your_form').on('event_name', {element_Selector}, callback_function)
},
off_Events: function() {
$('your_form').off('event_name', {element_Selector}, callback_function)
}
用于动态对象。在创建元素时添加事件,并在销毁元素之前删除这些事件。