问题代码:
首先看下面一段代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="content-type" />
<script src="jquery-1.3.2.js" type="text/javascript">
</script>
<style type="text/css">
#inner {
margin:0 auto;
width:150px;
height:50px;
border:1px solid green;
}
</style>
<script type="text/javascript">
$(function(){
$("#inner").click(function(){
//错误,引起内存泄露
$("#test")[0].innerHTML="";
//正确做法
//$("#test").empty();
});
});
</script>
<title>测试</title>
</head>
<body>
<div style="height:500px;width:500px;border:1px solid red;padding-top:100px;" id="test">
<div id="inner">click to remove me</div>
</div>
</body>
</html>
场景:
inner div 就是常见的我们可能使用 ajax 从服务器动态构造的元素,或者注入的片断html,效果为点击 inner 后就把它以及它的兄弟清除出去,依照传统的思路,直接 innerHTML =“” 就好了 ,可能你会想到所有删除元素的事件监听器应该清楚掉,但是对于除了 ie6 (引起内存泄露)以外的浏览器,清除事件监听器不是必要的 。
jquery 机制:
但是可以确定的是在 jquery 中用 innerHTML 的方法来清空元素,是必然会导致内存泄露的,由于 jquery 对于同一元素多事件处理没有直接采用浏览器事件模型,而是自己缓存事件,遍历触发,以及便于 trigger 程序触发 :
// Init the element's event structure
var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
jQuery.event.handle.apply(arguments.callee.elem, arguments) :
undefined;
});
采用 data 方法,将一些数据关联到了元素上面,上述事件即是采用该机制缓存事件监听器。
那么就可以知道,直接 innerHTML=“” 而不通知 jquery 清空与将要删除元素关联的数据,那么这部分数据就再也释放不了了,即为内存泄露。
解决:
jquery 已经想到了这一方面,提供了 empty 函数,其思想就是,对节点的所有子,孙,重孙.....节点( $("*",this) ),先清空它们关联的数据,再进行节点的删除:
remove: function( selector ) {
if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
// Prevent memory leaks
jQuery( "*", this ).add([this]).each(function(){
jQuery.event.remove(this);
jQuery.removeData(this);
});
if (this.parentNode)
this.parentNode.removeChild( this );
}
},
empty: function() {
// Remove element nodes and prevent memory leaks
jQuery(this).children().remove();
// Remove any remaining nodes
while ( this.firstChild )
this.removeChild( this.firstChild );
}
本文探讨了使用jQuery时如何避免内存泄露的问题。通过分析innerHTML方法导致内存泄露的原因,对比正确的元素清除方式empty(),揭示了jQuery内部事件处理机制。并提供了解决方案。

403

被折叠的 条评论
为什么被折叠?



