`

利用"事件上提" 来简化事件注册(防止潜在的内存泄露).

阅读更多
众所周知, 浏览器中内存泄露以及内存无法回收(两者不是一回事,很多人都把他们弄混淆了),常常是由于对dom元素注册事件不当引起的.

通常的解决方案是, 自行实现一套 添加事件, 移除事件 以及删除dom元素的机制.
为dom元素添加事件时, 同时记录 这个事件 以及对应的函数,
在删除dom元素时, 先移除dom元素上已经添加的事件 再删除dom元素本身.

而当页面中添加了事件监听的dom元素很多时, 移除元素变得很麻烦.
例如 一个div 里面有个form form里有多个元素都添加了事件.
那么移除这个div时, 就要先去移除他下面每一个元素上的事件 然后再移除这个div.

这种做法很多时候是必须的, 而且自己写一个"深度遍历子节点,并移除其事件"的函数也并不是很困难.

但是 在很多时候 这种做法是可以避免的, 避免的方法就是, 把事件监听注册到更上层的dom元素中.
并且在事件函数中 通过 event.target/event.srcElement 来 事件发生在哪个元素上,然后来执行相关的方法.
这样 在移除元素时 只要移除这个元素以及它上面的事件 就可以了, 而不必执行(或者少量的执行)"移除所有子节点事件"的动作了.


见下面的例子 :


  <table width="300" border="1"  onclick="showDetail(event)"> 
  <tr>
	<td>1</td>
	<td>Tom</td>
	<td><input type="button" value="详细信息" userid="1" /></td>
  </tr>
  <tr>
	<td>2</td>
	<td>Kate</td>
	<td><input type="button" value="详细信息" userid="2"  /></td>
  </tr>
  <tr>
	<td>3</td>
	<td>John</td>
	<td><input type="button" value="详细信息"  userid="3" /></td>
  </tr>
  </table>



在这个例子中, 实际上事件只是注册在table上, 而没有在"input type="button"上.

"showDetail" 可以这样写

	function showDetail_b(event) {
		event=event||window.event;
		var target=event.target||event.srcElement;
		if ( String(target.tagName).toLowerCase()=='input' &&  target.value=="详细信息") {
			showUserDetail(target.getAttribute('userid') );
		}
	}



当然 这种做法不是绝对的, 有时候这么做很可能让代码变得臃肿冗长.
到底是否使用"事件上提"的做法 要根据实际情况来选择.
不过 根据我的以往经验, 在列表(table)中, 使用这种技术非常合适.
因为 列表有着"行与行之间模型一致"(只是数据不一致,结构一致)的特点.

例如,下面的效果, 都可以通过在 table上注册事件来实现:

1 点击行, 行变色  (不必在 tr 上注册点击事件)
2 点击行中的某个按钮 (不必在 tr 里的 button 上注册点击事件)
3 鼠标经过行时 行变色 (不必在 tr上注册 mouseover/mouseout 事件, 而是可以在table上注册mousemove事件)
4 还有关于单元格的 很多效果.....

当然,在非列表里 这种做法也有很多的用武之地.
总之 合理的利用"事件上提"的方法, 可以增强dom元素和事件的可控性, 有效的防止内存泄露和内存无法回收的情况.




分享到:
评论
20 楼 zhangxi123 2008-08-09  
jQuery 对这些东西实现的非常好!
19 楼 yerba 2008-08-04  
这个设计确实不好,现在的系统是由几个新来的员工完成,校验这块普遍喜欢使用onblur,改起来很困难。
不过谢谢你的建议
18 楼 fins 2008-08-01  
不是所有事件都能上提的
这个blur 就不适合上提

但是 你关于校验的这个设计不好

建议修改一下设计吧

不能强迫用户"必须输入正确 才可离开当前编辑器"
这个设计非常非常不人性化 不友好
17 楼 yerba 2008-08-01  
onblur这种时间如何上提?
开发人员经常用onblur,当这个时间发生在两个都需要验证空的text上,切换会死锁,如果上提的话,如何注册这种时间?
16 楼 trarck 2008-07-30  
IE下的内存泄露原因就是循环引用,IE的垃圾回收器不能很好处理这种引用。
会产生泄露的循环引用,只有孤立的DOM对象(脱离DOM树)。
孤立的DOM对象间的循环引用,孤立的DOM对象与JS对象的循环引用。
为什么是孤立的DOM对象呢?在离开页面时(刷新,跳转)会删除整个DOM树,在DOM树上的对象也会被删除,就算有循环引用,此时被打断。
孤立的DOM对象有:一、用JS创建但未加入DOM树。二、从DOM树中删除的。
所以避免泄露,就尽量不要让这样的DOM对象产生。
有时候这样对象又不可避免,那就不要让这样对像产生循环引用。
最常见的循环引用是由闭包产生,其执行环境中的变量(包括参数)引用了DOM对象。
15 楼 rainchen 2008-07-28  
只有Gmail这种“大型”JS应用,才需要担心这种问题。曾经试过用一个IE开着GMAIL,一个晚上后,内存占用上G
14 楼 fins 2008-07-28  
这种情况其实没必要

不要对内存泄露太担心
1 不是所有的 dom上注册事件 都会引起内存泄露
2 如果不是大范围的使用 "使用js动态构建页面"的技术 内存泄露也泄露不了多少 无所谓的
13 楼 any_520 2008-07-28  
怪我问的问题太无脑了。。。
在什么时候会出现删除dom元素情况呢,我现在用jsp做简单开发(页面上有‘编辑’,‘保存’,‘删除’,‘上报’等简单按钮),会出现 fins大 说的内存泄露和内存无法回收的情况吗?
我们都是为每个按钮编写一个js方法的。
12 楼 fins 2008-07-28  
为了防止内存泄露 和内存无法回收的情况发生啊
11 楼 any_520 2008-07-28  
fins大,能否解释一下为什么“在删除dom元素时, 先移除dom元素上已经添加的事件 再删除dom元素本身. ”
10 楼 popl2003 2008-07-25  
是不是出现出所谓"一个系统一个页面"的情况吧.也就是很少跳转页面.比较纯Ajax情况.
9 楼 gaizaozhe 2008-07-25  
比较好奇:
在什么情况下会出現内存无法回收,什么情况下会内存泄露.
8 楼 fins 2008-07-24  
to jianfeng008cn :

简单点说:


内存无法回收 : 页面内的元素或对象已经销毁,但是却没有被回收,直到刷新页面后才回收


内存泄露: 同上.但更严重的是:刷新页面之后也不回收

7 楼 fins 2008-07-24  
如果你愿意 一个一个元素的注册事件 在页面关闭(unload) 时再一个一个的移除这些事件
那么你的做法没什么不好的

6 楼 popl2003 2008-07-24  
如果不在table里注册,在页面加载结束之后再对结点,再事件进行注册呢; 会有什么好与不好啊?
5 楼 jianfeng008cn 2008-07-23  
引用
众所周知, 浏览器中内存泄露以及内存无法回收(两者不是一回事,很多人都把他们弄混淆了),常常是由于对dom元素注册事件不当引起的.



能否也像该文一样清晰明了的说明下呢
4 楼 Army 2008-07-23  
好文,以前看过一篇类似的,不过比较简单,fins叙述的清晰明了。
3 楼 fins 2008-07-23  
“事件委托(事件代理)” 呵呵 笨笨狗果然是理论和实践都很牛

Quake Wang :
原来你就是 javaeye 传说中的 第三者 ???

嘿嘿
2 楼 QuakeWang 2008-07-23  
不错,学到了一招,可以改进JavaEye的博客管理界面中在tr上的mouseover事件
1 楼 笨笨狗 2008-07-23  
这个技巧是很常见的,Prototype就为实现这个提供了不少便利,比如event.element()、element.macth('css选择符')。
关于这个有个名词,那就是“事件委托(事件代理)”,在有的情况下这还是必须的,比如,你的子元素会动态增减,那么显然单独为每个子元素设置事件那是非常浪费也非常不可取的,这个时候放到父元素上,好处就显而易见了。

相关推荐

    HTD_PC模拟器内存分析工具 (版本号:3.3).rar

    总的来说,HTD_PC模拟器内存分析工具(版本号:3.3)是一款强大的开发辅助工具,它简化了对模拟器内存的分析过程,提供了高效的数据搜索和修改能力,对于提升开发效率和软件质量有着显著的帮助。无论是初级开发者...

    heapmemview,进程内存查看工具,亲测64位可用,不好找的,贡献出来,然后我也搞点可下载的积分

    今天,我们将深入探讨一个名为“heapmemview”的工具,这是一款专用于查看进程内存的实用程序,尤其值得一提的是,它已被证实可以在64位操作系统上正常工作。 heapmemview的主要功能是提供一个直观的界面,让用户...

    营销高手五菱,需要电商卖车.zip

    2. 安全支付:保障消费者在电商平台上的支付安全,防止信息泄露。 3. 物流配送:解决大型商品(如汽车)的物流配送问题,包括运输、安装、售后服务等。 4. 售后服务:建立完善的线上售后服务体系,解决用户在购车后...

    observatory:具有完整 jquery 事件支持的快速 pubsub 总线

    - **解除订阅(Unsubscribe)**: 当不再需要监听特定事件时,可以使用 `bus.unsubscribe('event:name', callback)` 来取消订阅,以避免内存泄漏和不必要的处理。 **文档与演示** 尽管天文台具有强大的功能,但...

    metasploit 详解(英文)很难得的源码分析

    - **漏洞扫描**:自动识别目标系统上的潜在漏洞。 - **漏洞利用**:根据扫描结果选择合适的攻击模块来实施攻击。 - **后利用技术**:在成功获得访问权限后,可以进行进一步的数据收集、权限提升等操作。 - **社会...

    AndroidKiller_v1.3.1.rar

    在安全分析时,可以检测潜在的恶意代码或隐私泄露问题;而在优化过程中,通过修改XML布局或资源文件,可以提高应用的运行效率和用户体验。 总结来说,"AndroidKiller_v1.3.1"是一款强大的Android应用开发和分析工具...

    大数据-算法-漏磁检测永磁铁磁回路的数学模型研究.pdf

    5. **提离值与非铁磁性材料**:在励磁过程中,允许存在一定量的提离值(即永磁体与管道间的间隙),这可能会影响磁场强度。此外,使用非铁磁性材料作为励磁装置可以调整磁场特性。 6. **电磁铁替代永磁体**:为了...

    运营探讨--ipv6安全浅析

    所以,内网的网络设备要依靠隐私扩展机制,通过周期性的地址改变,防止内部网络信息的泄露。 设定精细的过滤策略 面对IPv6地址结构以及相关协议的改变,防火墙或者网络边界设备需要设定更加精细的过滤规则。 ...

    代码审查九句真言-pdf

    - 考虑使用内存检测工具(如Valgrind)辅助查找潜在的内存泄漏。 #### 三、函数调用要小心,需要看看返回值。 - **核心思想**:每次调用函数后都应该检查其返回值,以确保调用成功并采取适当的后续措施。 - **...

    Ctrlpanel-crx插件

    在安装过程中,用户应该确保从可信赖的源获取此文件,以防止恶意软件的入侵。 总的来说,Ctrlpanel-crx插件是Ctrlpanel.io用户的一款实用工具,它通过集成登录、安全密码管理和账户管理功能,提升了用户在Web平台上...

    通过对编码实现防泄漏功能加密

    即通过配对编码(pair encodings)技术来构建泄漏弹性功能加密(Leakage-Resilient Functional Encryption,简称LR-FE)框架,尤其针对连续内存泄漏(Continual Memory Leakage,简称CML)模型。该模型允许在用户...

    动易网站的运用

    值得一提的是,动易BizIdea2.5版与支付宝系统的全面整合,使得商家能够共享支付宝的庞大用户群,拓展潜在客户,挖掘更多商业机会,展现了动易网站管理系统在电商领域的应用潜力。 综上所述,动易网站管理系统凭借其...

Global site tag (gtag.js) - Google Analytics