网址:
http://fins.javaeye.com/blog/173818

2008-03-20更新一个临时解决方案.

测试发现,Ext2.02在IE下无法正常释放被删除的元素(当该元素被注册了事件时)
经过分析 发现ext事件机制中的一个bug
(
bug 具体描述见: http://fins.javaeye.com/blog/173218
测试使用工具见: http://fins.javaeye.com/blog/172891
)

使用 el.on(eventName, fn) 为el添加事件
调用 Ext.destroy(el) 方法移除el
此时,如果fn为全局类型,或者是被全局对象引用, 那么会使el元素成为孤立节点,无法彻底移除.

而如果在 Ext.destroy(el) 之前, 调用 el.un(eventName, fn) 移除添加的事件,
那么就可以彻底移除. 但是直接使用 Ext.destroy 才是ext中描述的正确做法,
切ext内部也都是这样使用的, 所以应该将解决问题的着手点放在 el.on 和 Ext.destroy方法上.

Javascript代码
  1. =============================
  2. 销毁元素的方法(很简单)
  3. =============================
  4. Ext.destroy(el){
  5. el.removeAllListeners();
  6. el.removeNode();
  7. }
=============================
销毁元素的方法(很简单)
=============================
Ext.destroy(el){el.removeAllListeners();el.removeNode();
}

经过测试 Ext.destroy el.removeNode 均无问题. 核心问题在 事件机制. 下面详细分析一下.

Javascript代码
  1. =============================
  2. 给一个元素添加事件
  3. =============================
  4. Element.on(eventName, fn) {
  5. el=this;
  6. 调用 EventManager.on( el,eventName, fn ){
  7. 调用 EventManager.listener( el,eventName, fn ){
  8. 包装   h <---- fn
  9. 缓存  fn._handlers <---- [ [h]  ]
  10. 调用 Ext.Event.on( el,eventName, h )  {
  11. 包装   wfn <---- h
  12. 缓存  Ext.Event._listeners  <---- [ el , eventName, h, wfn ]
  13. el.addEvent( wfn )
  14. }
  15. }
  16. }
  17. }
  18. 注意:真正注册到el上的事件是wfn
=============================
给一个元素添加事件
=============================
Element.on(eventName, fn) {el=this;调用 EventManager.on( el,eventName, fn ){调用 EventManager.listener( el,eventName, fn ){包装   h <---- fn缓存  fn._handlers <---- [ [h]  ]调用 Ext.Event.on( el,eventName, h )  {包装      wfn <---- h缓存  Ext.Event._listeners  <---- [ el , eventName, h, wfn ]el.addEvent( wfn ) }}}
}
注意:真正注册到el上的事件是wfn
Javascript代码
  1. =============================
  2. 移除一个元素的事件
  3. =============================
  4. Element.un(eventName, fn) {
  5. el=this;
  6. 调用 EventManager.un( el,eventName, fn ){
  7. 调用 EventManager.stopListener( el,eventName, fn ){
  8. 取得之前缓存的 h <---- fn._handlers
  9. 删除 fn._handlers  缓存内的相关数据
  10. 调用 Ext.Event.un( el,eventName, h )  {
  11. 取得之前缓存的  wfn  <---- Ext.Event._listeners
  12. el.removeEvent( wfn )
  13. 删除 Ext.Event._listeners 缓存内的相关数据
  14. }
  15. }
  16. }
  17. }
=============================
移除一个元素的事件
=============================
Element.un(eventName, fn) {el=this;调用 EventManager.un( el,eventName, fn ){调用 EventManager.stopListener( el,eventName, fn ){取得之前缓存的 h <---- fn._handlers 删除 fn._handlers  缓存内的相关数据 调用 Ext.Event.un( el,eventName, h )    {取得之前缓存的  wfn  <---- Ext.Event._listenersel.removeEvent( wfn ) 删除 Ext.Event._listeners 缓存内的相关数据 }}}
}
Javascript代码
  1. =============================
  2. 移除一个元素的所有注册的事件
  3. =============================
  4. Element.removeAllListeners() {
  5. el=this;
  6. 调用 Ext.Event.purgeElement(el){
  7. 取得缓存中所有的和el相关的信息   l[] <---- Ext.Event._listeners
  8. <循环开始 l[] >
  9. 从 l中取得  eventName <---- l[i];
  10. 从 l中取得  h <---- l[i];
  11. 调用 Ext.Event.un( el,eventName, h )  {
  12. 取得之前缓存的  wfn  <---- Ext.Event._listeners
  13. el.remove( wfn )
  14. 删除 Ext.Event._listeners 缓存内的相关数据
  15. }
  16. <循环结束>
  17. }
  18. }
=============================
移除一个元素的所有注册的事件
=============================
Element.removeAllListeners() {el=this;调用 Ext.Event.purgeElement(el){取得缓存中所有的和el相关的信息   l[] <---- Ext.Event._listeners<循环开始 l[] >从 l中取得  eventName <---- l[i];从 l中取得  h <---- l[i];调用 Ext.Event.un( el,eventName, h )    {取得之前缓存的  wfn  <---- Ext.Event._listenersel.remove( wfn ) 删除 Ext.Event._listeners 缓存内的相关数据 }<循环结束>}}

==============================

产生问题的原因
执行Element.removeAllListeners时没有调用 EventManager.stopListener中的
"删除 fn._handlers 缓存内的相关数据 "

导致在IE下 当 fn 为全局对象 或者是被引用时, 元素无法被正确移除.

-----------------------------------------
如果只是简单的修改 Element.removeAllListeners

让其 调用 Ext.Event.un 时 改成调用 EventManager.stopListener 是不行的

因为 Element.removeAllListeners 调用 Ext.Event.un 时 ,传递的函数参数是h, 而不是最初的fn
但是 EventManager.stopListener需要得到 最初的fn.

-----------------------------------------
现在的情况是 从 fn 能找到h (fn._handlers) ,但是 通过h无法找到fn
缓存Ext.Event._listeners 中也没有存放 最初的fn.

-----------------------------------------
也许可以考虑在 removeAllListeners 或 purgeElement 中对 fn._handlers 进行清除,但是 拿不到 最初的fn

-----------------------------------------
如果之前 强制 做一个引用, 例如 h._core =fn;
然后在 Element.removeAllListeners 加以利用 利用完之后 再清除, 似乎看起来不错
但是我试了 ,失败 !!!!
具体原因我也说不清

==================================

我觉得 如果要解决 这个bug 确实要对ext的整个事件机制做一番大改动.(恕我直言,ext的这套事件机制真的有点太.... )

以上是我最近研究的成果
发上来和大家分享,如果说的不对 请务必一定马上纠正我, 以免误人子弟 谢谢大家了

======================================
下面附上刚刚写出的 解决方案,请大家拍砖, 我想肯定还有更好的方法.

第一步 ========================
EventManager.js 153行

Javascript代码
  1. //修改 Ext.EventManager的 私有方法 listen
  2. //   E.on(el, ename, h);
  3. // 改为如下 (即,多传一个最初的 fn)
  4. E.on(el, ename, h , fn);
//修改 Ext.EventManager的 私有方法 listen
//   E.on(el, ename, h);
// 改为如下 (即,多传一个最初的 fn)E.on(el, ename, h , fn);

第二步 ========================

ext-base.js 227行

Javascript代码
  1. //修改 Ext.lib.Event 的  addListener 和 removeListener 方法
  2. addListener: function(el, eventName, fn , ofn) {
  3. el = Ext.getDom(el);
  4. if (!el || !fn) {
  5. return false;
  6. }
  7. if ("unload" == eventName) {
  8. unloadListeners[unloadListeners.length] =
  9. [el, eventName, fn];
  10. return true;
  11. }
  12. // prevent unload errors with simple check
  13. var wrappedFn = function(e) {
  14. return typeof Ext != 'undefined' ? fn(Ext.lib.Event.getEvent(e)) : false;
  15. };
  16. var li = [el, eventName, fn, wrappedFn,ofn];
  17. var index = listeners.length;
  18. listeners[index] = li;
  19. this.doAdd(el, eventName, wrappedFn, false);
  20. return true;
  21. },
  22. removeListener: function(el, eventName, fn) {
  23. var i, len;
  24. el = Ext.getDom(el);
  25. if(!fn) {
  26. return this.purgeElement(el, false, eventName);
  27. }
  28. if ("unload" == eventName) {
  29. for (i = 0,len = unloadListeners.length; i < len; i++) {
  30. var li = unloadListeners[i];
  31. if (li &&
  32. li[0] == el &&
  33. li[1] == eventName &&
  34. li[2] == fn) {
  35. unloadListeners.splice(i, 1);
  36. return true;
  37. }
  38. }
  39. return false;
  40. }
  41. var cacheItem = null;
  42. var index = arguments[3];
  43. if ("undefined" == typeof index) {
  44. index = this._getCacheIndex(el, eventName, fn);
  45. }
  46. if (index >= 0) {
  47. cacheItem = listeners[index];
  48. }
  49. if (!el || !cacheItem) {
  50. return false;
  51. }
  52. this.doRemove(el, eventName, cacheItem[this.WFN], false);
  53. fn=listeners[index][4];
  54. if (fn){
  55. var id = Ext.id(el), hds = fn._handlers, hd = fn;
  56. if(hds){
  57. for(var i = 0, len = hds.length; i < len; i++){
  58. var h = hds[i];
  59. if(h[0] == id && h[1] == eventName){
  60. hd = h[2];
  61. hds.splice(i, 1);
  62. break;
  63. }
  64. }
  65. }
  66. }
  67. delete listeners[index][this.WFN];
  68. delete listeners[index][this.FN];
  69. listeners.splice(index, 1);
  70. return true;
  71. },
//修改 Ext.lib.Event 的  addListener 和 removeListener 方法addListener: function(el, eventName, fn , ofn) {el = Ext.getDom(el);if (!el || !fn) {return false;}if ("unload" == eventName) {unloadListeners[unloadListeners.length] =[el, eventName, fn];return true;}// prevent unload errors with simple checkvar wrappedFn = function(e) {return typeof Ext != 'undefined' ? fn(Ext.lib.Event.getEvent(e)) : false;};var li = [el, eventName, fn, wrappedFn,ofn];var index = listeners.length;listeners[index] = li;this.doAdd(el, eventName, wrappedFn, false);return true;},removeListener: function(el, eventName, fn) {var i, len;el = Ext.getDom(el);if(!fn) {return this.purgeElement(el, false, eventName);}if ("unload" == eventName) {for (i = 0,len = unloadListeners.length; i < len; i++) {var li = unloadListeners[i];if (li &&li[0] == el &&li[1] == eventName &&li[2] == fn) {unloadListeners.splice(i, 1);return true;}}return false;}var cacheItem = null;var index = arguments[3];if ("undefined" == typeof index) {index = this._getCacheIndex(el, eventName, fn);}if (index >= 0) {cacheItem = listeners[index];}if (!el || !cacheItem) {return false;}this.doRemove(el, eventName, cacheItem[this.WFN], false);fn=listeners[index][4];if (fn){var id = Ext.id(el), hds = fn._handlers, hd = fn;if(hds){for(var i = 0, len = hds.length; i < len; i++){var h = hds[i];if(h[0] == id && h[1] == eventName){hd = h[2];hds.splice(i, 1);break;}}}}delete listeners[index][this.WFN];delete listeners[index][this.FN];listeners.splice(index, 1);return true;},

Ext2.02事件机制缺陷分析,以及解决方案 (fins)相关推荐

  1. 车轮件缺陷分析及设计优化 | 智铸超云案例分享

    01 产品介绍 产品结构 该铸件为一体成型的车轮件,产品平均壁厚为5.0mm,直径为530mm,结构基本符合中心对称,在轮辐根部和车轮外圈加工面上不允许存在明显气孔缺陷. 工艺参数 合金材料为AM60 ...

  2. android 事件机制总结

    http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html http://www.cnblogs.com/sunzn/archive/20 ...

  3. spring boot 源码分析(七) 事件机制 之 SpringApplicationEvent

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 前面的文章我们讲解了一下spring boot配置文件加载的相关源码分析,下面我们将从源码角度讲解一下spring  ...

  4. Javascript事件机制兼容性解决方案

    本文的解决方案可以用于Javascript native对象和宿主对象(dom元素),通过以下的方式来绑定和触发事件: 或者 var input = document.getElementsByTag ...

  5. Qt 事件机制源码分析 QApplication exec 源码分析 多图超级详细

    前言: 不熟悉qt 源码结构的 可以先看这一篇 点我点我点我 写qt 的都知道 以下代码, 这段代码究竟的运行机制是怎么样的 咱们一步一步的看 QApplication a(argc, argv);Q ...

  6. B/S系统常见缺陷整理和解决方案

    最近部门整理了今年所有项目测试团队提出的BUG,筛选了几十个作为常规通用的缺陷,我根据这些缺陷内容,去掉和业务相关的知识,整理出了一份缺陷描述和解决方案. 其实WEB系统中常规的缺陷分类后也就那么多, ...

  7. 2021年大数据Spark(五十二):Structured Streaming 事件时间窗口分析

    目录 事件时间窗口分析 时间概念 ​​​​​​​event-time ​​​​​​​延迟数据处理 ​​​​​​​延迟数据 ​​​​​​​Watermarking 水位 ​​​​​​​官方案例演示 事件 ...

  8. 测试缺陷分析务实篇-转

    测试缺陷分析务实篇 2008-08-28 作者:罗耀秋 来源:网络   摘要: 测试活动作为IT项目和产品开发一个重要的环节,通过发现产品或组件的缺陷,并反馈给开发组修复验证这些缺陷,从而在一定程度上 ...

  9. .net组件开发系列之武术系列 武术招数 控件生命周期与控件事件机制

    .net组件开发系列之武术系列 武术招数 控件生命周期与控件事件机制一.控件生命周期 先回述上篇,可能表述没有不清晰,也可能跨度大了点,好的,我们来一个循序渐进过程,大家都知道,武术都有招术的,先出什 ...

最新文章

  1. 安卓平板排行榜_shopee虾皮台湾安卓市场, shopee虾皮直播下载
  2. 10个职场故事,让人不得不看
  3. 数控铣削图案及编程_数控铣加工比普铣的优势,大多数人选择数控铣的原因
  4. java常见基础面试题
  5. 电脑桌面计算机被隐藏怎么恢复,电脑桌面隐藏文件怎样恢复
  6. 三个比较经典的策略: Dual Thrust、R-Breaker、Dynamic Breakout II
  7. TCP自时钟/拥塞控制/带宽利用之脉络半景解析
  8. Spring之IOC自动装配解析
  9. 记一道80%的人会答错的牛X面试题!
  10. 全功能的屏幕截图工具 - PicPick
  11. html自动关闭当前页面,html如何关闭当前页面
  12. json的存在意义(json和String的区别)
  13. 【janus 】openresty +janus
  14. GPIO口配置为上拉,下拉输入
  15. 走向Web渗透工程师
  16. 从零开始的计算机学习
  17. l351墨水灯和缺纸灯闪烁_爱普生L351有墨水,可缺墨的灯一直闪,怎么解决?
  18. 质量管理工具_老七工具之一__帕累托图
  19. android车载支持格式,安卓全面屏适配攻略(适配超长车载主机)
  20. 安卓开源画图app“MK画图”增加水印功能,呵呵

热门文章

  1. 多数据源(Springboot)
  2. 民营企业IT项目管理之路
  3. Pyhton操作Neo4j图数据库实践(南北朝隋唐历史北朝主要人物知识图谱)
  4. 三款比较有名的终端浏览器(w3m , links2 ,lynx)
  5. sheepdog--介绍
  6. python将txt中的内容导入到excel
  7. Squid代理服务器——传统代理,透明代理(实践!)
  8. Python之父:python根本没有那么难,边玩边学
  9. 人工智能OCR文字识别研究
  10. YSZI的微信公众号导航软件按装方法