jQuery实时刷新引发的内存泄漏
工作中需要页面数据的实时刷新,采用了jQuery的ajax实现,前后台使用JSON格式数据通信。有两个定时器,每3s刷新一次,运行一段时间后发现页面内存占用了900+M,太恐怖了。调试步骤如下:
1、ajax回传数据后不做任何操作,在success中直接return,发现内存持续增长,没有缓解,初步断定是jQuery的问题,jQuery采用了1.5.2版本,查找各方帖子,都说是XMLHttpRequest对象的问题,需要清空该对象,jQuery唯一能做的就是使用:complete: function (XHR, TS) { XHR = null; } 。推断XMLHttpRequest依然没有释放。
2、更新jQuery版本,将版本更换到比较稳定的jQuery1.2.6版本,发现内存不再疯狂增长,开始了有增有落,这是个好现象。
3、去掉步骤1中增加的return; 放开后便的js继续执行。发现了内存依然缓慢增长,虽然增幅不大,但是还在增长,页面长期停留肯定依然会出现问题。继续跟踪js代码,发现页面元素的click事件每次刷新时都重新注册了一次,怀疑是他的问题,遂关闭click时间注册,页面刷新后发现内存不再持续增长,宾果! 原来是click多次注册的问题。后来将click事件注册放到了init方法中,页面初始化函数仅执行一次,初始化页面结构,注册各种事件,刷新函数定时刷新页面数据。在多次测试后均没有重现问题。本着预防为主防止结合的方针,最后在页面中也增加了定时刷新整体页面的定时器,不过设置了一个小时的时间。大可不必担心页面整体刷新降低了用户体验。
4、页面上还有个日志显示的模块,也是定时刷新的,长时间运行后也会出现问题。为了显示实时日志,系统采用ajax定时取数据,然后构造<li><a></></li>界面元素,append到相应的<ui></ui>中去。经过测试发现大批量的操作节目元素也同样会导致页面占用内存的持续攀升,后来更新为初始化固定数量的界面元素,每次刷新仅仅给不同的元素赋值,不再手动的新建然后删除元素,发现内存被限制在了一个范围内,不再持续增长。
5、页面中还需要注意到的一点是适用jquery的 html()函数,该函数不是基于innerHTML实现的,大量使用同样也会导致系统性能下降,可以自己重写一下:
/** jquery html方法导致内存增长问题优化 请调用html2方法 $("#id").html2() **/ $(function(){ window.recycler = (function() { var t = document.createElement('div'); t.id = 'recycler'; return t; })(); jQuery.fn.extend({ freeMemory: function() { var jel = $(this); jel.unbind(); var cld = jel.children(), len = cld.size(); if (len) { $.each(cld, $.freeMemory); } var rel = jel.get(0); if (rel && window.recycler){ window.recycler.appendChild(rel); window.recycler.innerHTML = ''; } delete rel; rel = null; delete len; len = null; delete cld; cld = null; delete jel; jel = null; }, html2: function(value, raw) { if ((typeof raw === 'undefined' || typeof raw === 'Undefined' || !raw) && typeof value === 'string') { this.children().each(jQuery.freeMemory); if (this[0] && typeof this[0].innerHTML != 'undefined' && typeof this[0].innerHTML != 'Undefined') { this[0].innerHTML = value; delete value; value = null; return this; } } return value === undefined ? (this[0] ? this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : null) : this.empty().append( value ); } }); });
6、使用委托替代事件注册
页面中如果元素过多,且需要为每个元素注册相同的click事件,这个时候我们优先考虑到使用委托机制,将需要注册的click事件注册到元素的上层元素或者顶层元素,这样我们就节省了大量的click注册事件。
总结:页面定时刷新导致页面占用系统内存会持续攀升。
1、更换更稳定的jQuery版本,版本不是越高越好啊
2、防止出现事件重复注册情况(少量的重复注册不会影响性能,如果把注册事件放到了定时器中注册,就得小心了)。
3、不要频繁的新建、删除界面元素,可以初始化元素然后在复不同的值。
4、大量使用jquery.html()函数。
5、使用委托替代直接的元素事件注册。