2007年6月15日

JScript的内存泄漏之后续篇

JScript Memory Leaks in Microsoft IE solution 2

正像我上篇文章翻译的一样,Microsoft Internet Explorer 在DOM对象增加事件句柄后会带来内存泄漏的问题。上篇文章也给出了解决方案,但是如果在开发者未知该何时调用这个净化程序时,一般开发者会加入类似的代码:

if ( Nebula.isIE ) {
  window.attachEvent("onunload", function () {
    Nebula.clearEvent ( document.body );
  });
}

这里的Nebula.clearEvent就是上述的净化程序,它在你离开页面或刷新页面时触发,这很重要。比如你正在浏览Gmail,但不知道什么原因导致你必须刷新gmail,这时如果不调用净化程序内存仍然是得不到释放。

是的,你也许也发现了我们传进去的是document.body,这意味着要对整个html文档进行递归地循环地“净化”,效率是很低的。于是我改进了这个方法。

/**
 * The basic global namespace
 * @constructor
 */
window.Nebula = {
  /**
   * get the Nebula lib 's version
   * @type {string}
   */
  version: "1.1.0.0",
  
  /**
  * Boolean flag that navigator whether it is MCST IE
  * @type boolean
  */
  isIE: !!window.ActiveXObject,
  
  /**
  * Boolean flag that navigator whether it is Apple Safari
  * @type boolean
  */
  isSafari: navigator.userAgent.toLowerCase().indexOf("safari") > -1 ,
  
  /**
  * Boolean flag that navigator whether it is Opera
  * @type boolean
  */
  isOpera: navigator.userAgent.toLowerCase().indexOf("opera") > -1 ,
  
  /**
   * event names
   */
  _eventList: ["onbeforecut", "onblur", "onclick", "oncontextmenu", "oncut", 
     "ondblclick", "ondeactivate", "ondragenter", "ondragleave", "ondragover",
     "ondrop",  "onfocus", "onfocusin", "onfocusout", "onhelp", "onkeydown", 
     "onkeypress", "onkeyup", "onmousedown", "onmouseenter", "onmouseleave", 
     "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel",
     "onmove", "onmoveend", "onmovestart", "onpaste", "onreadystatechange",
     "onresize", "onresizeend", "onresizestart", "onselectstart"
   ],
 
  
  /**
   * clear html element 's event handle, fix ie MEMORY LEAKS bug
   * @param d , the element of cleared
   */
  clearEvent: function (d) {
    var a, i, l, n;
    
    if (!d || !this.isIE) {
      return;
    }
    
    a = this._eventList;
    
    try{
      if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
          n = a[i];
          if (typeof d[n] === "function") {
            d[n] = null;
          }
        }
      }
      a = d.childNodes;
      if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
          this.clearEvent(d.childNodes[i]);
        }
      }
    }catch(ex){
      //alert(ex.message);
    }
  }
 
};



if ( Nebula.isIE ) {
  window.attachEvent("onunload", function () {
    Nebula.clearEvent ( document.body );
  });
}

我把DOM元素可能用到event列出来,然后去再去循环这些event,而不是DOM的所有属性。这样好处将会提高效率,减少数万次计算。

没有评论: