请选择 进入手机版 | 继续访问电脑版
收藏本站腾讯微博新浪微博
点点网模板设计大赛 phpchina

经典论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

蓝色理想 最新研发动态 用悬赏 三天解决问题 解决访问速度慢 论坛支持农历生日 - 给官方提建议

论坛活动及任务 归纳网站最新活动 地图任务 邮件更新任务:保护帐号安全

积分换实物,来参加蓝色理想积分兑换吧! 联系招聘客服 蓝色理想帮你找工作! 万元奖励等你拿——点点网模板设计大赛

查看: 3768|回复: 12

[ 共享 ] 关于Javascript的内存泄漏问题的整理稿(有兴趣的朋友一定要看看!) [复制链接]

yaohaixiao 楼主

会武术的科学家

实习版主

帖子
2051
体力
5602
威望
45
居住地
浙江省 杭州市
发表于 2008-4-13 09:29:30 |显示全部楼层
常规循环引用内存泄漏和Closure内存泄漏

要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理。

我记得原来在犀牛书《JavaScript: The Definitive Guide》中看到过,IE使用的GC算法是计数器,因此只碰到循环 引用就会造成memory leakage。后来一直觉得和观察到的现象很不一致,直到看到Eric的文章,才明白犀牛书的说法没有说得很明确,估计该书成文后IE升级过算法吧。在IE 6中,对于javascript object内部,jscript使用的是mark-and-sweep算法,而对于javascript object与外部object(包括native object和vbscript object等等)的引用时,IE 6使用的才是计数器的算法。

Eric Lippert在http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx一文中提到IE 6中JScript的GC算法使用的是nongeneration mark-and-sweep。对于javascript对算法的实现缺陷,文章如是说:

"The benefits of this approach are numerous, but the principle benefit is that circular references are not leaked unless the circular reference involves an object not owned by JScript. "

也就是说,IE 6对于纯粹的Script Objects间的Circular References是可以正确处理的,可惜它处理不了的是JScript与Native Object(例如Dom、ActiveX Object)之间的Circular References。

所以,当我们出现Native对象(例如Dom、ActiveX Object)与Javascript对象间的循环引用时,内存泄露的问题就出现了。当然,这个bug在IE 7中已经被修复了[http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html]。

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp 中有个示意图和简单的例子体现了这个问题:

  1. <html>
  2. <head>
  3. <script language = " JScript ">
  4. var myGlobalObject;
  5. function  SetupLeak()  // 产生循环引用,因此会造成内存泄露
  6. {
  7.     //  First set up the script scope to element reference
  8.     myGlobalObject  = document.getElementById("LeakedDiv");

  9.     //  Next set up the element to script scope reference
  10.     document.getElementById(" LeakedDiv ").expandoProperty  = myGlobalObject;
  11. }

  12. function  BreakLeak()  // 解开循环引用,解决内存泄露问题
  13. {
  14.     document.getElementById( " LeakedDiv " ).expandoProperty  = null ;
  15. }
  16. </script>
  17. </head>
  18. <body onload = "SetupLeak()"  onunload = "BreakLeak()">
  19. <div id = "LeakedDiv" ></div>
  20. </body>
  21. </html>   
复制代码


上面这个例子,看似很简单就能够解决内存泄露的问题。可惜的是,当我们的代码中的结构复杂了以后,造成循环引用的原因开始变得多样,我们就没法那么容易观察到了,这时候,我们必须对代码进行仔细的检查。

尤其是当碰到Closure,当我们往Native对象(例如Dom对象、ActiveX Object)上绑定事件响应代码时,一个不小心,我们就会制造出Closure Memory Leak。其关键原因,其实和前者是一样的,也是一个跨javascript object和native object的循环引用。只是代码更为隐蔽,这个隐蔽性,是由于javascript的语言特性造成的。但在使用类似内嵌函数的时候,内嵌的函数有拥有一个reference指向外部函数的scope,包括外部函数的参数,因此也就很容易造成一个很隐蔽的循环引用,例如:

DOM_Node.onevent ->function_object.[ [ scope ] ] ->scope_chain ->Activation_object.nodeRef ->DOM_Node。

[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp]有个例子极深刻地显示了该隐蔽性:

  1. <html>
  2. <head>
  3. <script language = "JScript">
  4. function  AttachEvents(element)
  5. {
  6.     //  This structure causes element to ref ClickEventHandler
  7.     //  element有个引用指向函数ClickEventHandler()
  8.     element.attachEvent("onclick", ClickEventHandler);

  9.     function  ClickEventHandler(){
  10.                  //  This closure refs element
  11.                  //  该函数有个引用指向AttachEvents(element)调用Scope,也就是执行了参数element。
  12.     }
  13. }

  14. function  SetupLeak()
  15. {
  16.     //  The leak happens all at once
  17.     AttachEvents(document.getElementById("LeakedDiv"));
  18. }
  19. </script>
  20. </head>
  21. <body onload = "SetupLeak()"  onunload = "BreakLeak()">
  22. <div id = "LeakedDiv"></div>
  23. </body>
  24. </html>
复制代码


还有这个例子在IE 6中同样原因会引起泄露

  1. function  leakmaybe() {
  2. var  elm  =  document.createElement("DIV");
  3.      elm.onclick  =  function(){
  4.          return   2   +   2 ;
  5.      }
  6. }

  7. for( var  i = 0 ;i < 10000;i ++){
  8.   leakmaybe();
  9. }
复制代码


关于Closure的知识,大家可以看看http://jibbering.com/faq/faq_notes/closures.html这篇文章,习惯中文也可以看看zkjbeyond的blog,他对Closure这篇文章进行了简要的翻译:http://www.blogjava.net/zkjbeyond/archive/2006/05/19/47025.html。之所以会有这一系列的问题,关键就在于javascript是种函数式脚本解析语言,因此javascript中“函数中的变量的作用域是定义作用域,而不是动态作用域”,这点在犀牛书《JavaScript: The Definitive Guide》中的“Funtion”一章中有所讨论。

http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555中也对这个问题举了很详细的例子。

一些简单的解决方案

目前大多数ajax前端的javascript framework都利用对事件的管理,解决了该问题。

如果你需要自己解决这个问题,可以参考以下的一些方法:

http://outofhanwell.com/ieleak/index.php?title=Main_Page:有个不错的检测工具

http://youngpup.net/2005/0221010713 中提到:可以利用递归Dom树,解除event绑定,从而解除循环引用:

  1. if (window.attachEvent){         
  2.     var clearElementProps = ['data','onmouseover','onmouseout','onmousedown','onmouseup','ondblclick','onclick','onselectstart','oncontextmenu'];         
  3.    
  4.     window.attachEvent("onunload", function(){            
  5.         var el;
  6.         for(var d = document.all.length;d--;){                  
  7.             el = document.all[d];                  
  8.                 for(var c = clearElementProps.length;c--;){                     
  9.                     el[clearElementProps[c]] = null;                  
  10.                 }              
  11.             }         
  12.         }
  13.     );      
  14. }                                                                                               
复制代码

                                                                                               
而http://novemberborn.net/javascript/event-cache一文中则通过增加EventCache,从而给出一个相对结构化的解决方案

  1. /*     
  2.     EventCache Version 1.0
  3.     Copyright 2005 Mark Wubben

  4.     Provides a way for automagically removing events from nodes and thus preventing memory leakage.
  5.     See <http://novemberborn.net/javascript/event-cache> for more information.
  6.    
  7.     This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
  8. */

  9. /*  
  10.     Implement array.push for browsers which don't support it natively.
  11.     Please remove this if it's already in other code  
  12. */
  13. if (Array.prototype.push == null ){
  14.     Array.prototype.push =  function (){
  15.          for (var i = 0;i<arguments.length;i ++){
  16.              this[this.length] = arguments[i];
  17.          };
  18.          return this.length;
  19.     };
  20. };

  21. /*     
  22.     Event Cache uses an anonymous function to create a hidden scope chain.
  23.     This is to prevent scoping issues.  
  24. */
  25. var EventCache = function (){
  26.      var listEvents=[];
  27.      return{
  28.         listEvents : listEvents,
  29.    
  30.         add: function(node, sEventName, fHandler, bCapture){
  31.             listEvents.push(arguments);
  32.         },
  33.    
  34.         flush: function (){
  35.              var i,item;
  36.              for (i = listEvents.length-1;i>=0;i=i-1 ){
  37.                 item=listEvents[i];
  38.                 if(item[0].removeEventListener){
  39.                     item[0].removeEventListener(item[1],item[2],item[3]);
  40.                 };
  41.                
  42.                 /* From this point on we need the event names to be prefixed with 'on"  */
  43.                 if(item[1].substring(0, 2)!="on" ){
  44.                     item[1]="on"+item[1];
  45.                 };
  46.                
  47.                 if(item[0].detachEvent){
  48.                     item[0].detachEvent(item[1], item[2]);
  49.                 };
  50.                
  51.                 item[0][item[1]]=null;
  52.             };
  53.         }
  54.     };
  55. }();
复制代码



使用方法也很简单:

  1. <script type="text/javascript">
  2. function addEvent(oEventTarget,sEventType,fDest){        
  3. if(oEventTarget.attachEvent){               
  4.      oEventTarget.attachEvent("on" + sEventType, fDest);       
  5. }
  6. elseif(oEventTarget.addEventListener){               
  7.      oEventTarget.addEventListener(sEventType, fDest, true);        
  8. }
  9. elseif(typeof oEventTarget[sEventType]=="function"){               
  10.      var fOld = oEventTarget[sEventType];               
  11.      oEventTarget[sEventType] = function(e){
  12.          fOld(e);
  13.          fDest(e);
  14.      };       
  15. }
  16. else {               
  17.      oEventTarget[sEventType] = fDest;       
  18. };
  19.        
  20. /* Implementing EventCache for all event systems */       
  21. EventCache.add(oEventTarget, sEventType, fDest, true);};

  22. function createLeak(){         
  23.      var body = document.body;       
  24.      function someHandler(){               
  25.          return body;       
  26.      };       
  27.          addEvent(body, "click", someHandler);
  28. };
  29.      
  30. window.onload = function(){      
  31.      var i = 500;      
  32.      while(i > 0){               
  33.           createLeak();               
  34.           i = i - 1;
  35.      }
  36. };
  37.      
  38. window.onunload = EventCache.flush;
  39. </script>                                                                                                       
复制代码
       
                                                               
http://talideon.com/weblog/2005/03/js-memory-leaks.cfm 一文中的方法类似:

  1. /*
  2. * EventManager.js
  3. * by Keith Gaughan
  4. *
  5. * This allows event handlers to be registered unobtrusively, and cleans
  6. * them up on unload to prevent memory leaks.
  7. *
  8. * Copyright (c) Keith Gaughan, 2005.
  9. *
  10. * All rights reserved. This program and the accompanying materials
  11. * are made available under the terms of the Common Public License v1.0
  12. * (CPL) which accompanies this distribution, and is available at
  13. * http://www.opensource.org/licenses/cpl.php
  14. *
  15. * This software is covered by a modified version of the Common Public License
  16. * (CPL), where Keith Gaughan is the Agreement Steward, and the licensing
  17. * agreement is covered by the laws of the Republic of Ireland.
  18. */

  19. //  For implementations that don't include the push() methods for arrays.
  20. if(!Array.prototype.push){
  21.     Array.prototype.push=function(elem){
  22.          this[this.length]=elem;
  23.     }
  24. }

  25. var  EventManager={
  26.     _registry: null,

  27.     Initialise: function(){
  28.          if(this._registry==null){
  29.              this._registry=[];

  30.              //  Register the cleanup handler on page unload.
  31.              EventManager.Add(window,"unload" ,this.CleanUp);
  32.          }
  33.     },

  34.     /*
  35.      * Registers an event and handler with the manager.
  36.      *
  37.      * @param  obj         Object handler will be attached to.
  38.      * @param  type        Name of event handler responds to.
  39.      * @param  fn          Handler function.
  40.      * @param  useCapture  Use event capture. False by default.
  41.      *                     If you don't understand this, ignore it.
  42.      *
  43.      * @return True if handler registered, else false.
  44.      */
  45.     Add: function(obj, type, fn, useCapture){
  46.          this.Initialise();

  47.          //  If a string was passed in, it's an id.
  48.          if(typeof obj=="string"){
  49.             obj = document.getElementById(obj);
  50.          }
  51.          if(obj==null || fn==null){
  52.             return  false ;
  53.          }

  54.          // Mozilla/W3C listeners?
  55.          if(obj.addEventListener){
  56.             obj.addEventListener(type, fn, useCapture);
  57.             this._registry.push({obj: obj, type: type, fn: fn, useCapture: useCapture});
  58.             return  true ;
  59.          }

  60.          //  IE-style listeners?
  61.          if(obj.attachEvent && obj.attachEvent("on" + type,fn)){
  62.             this._registry.push({obj: obj, type: type, fn: fn, useCapture: false });
  63.             return true ;
  64.          }

  65.          return false ;
  66.     },

  67.     /* *
  68.      * Cleans up all the registered event handlers.
  69.      */
  70.     CleanUp: function(){
  71.          for(var i=0;i<EventManager._registry.length;i++){
  72.              with(EventManager._registry[i]) {
  73.                  // Mozilla/W3C listeners?
  74.                  if(obj.removeEventListener) {
  75.                     obj.removeEventListener(type, fn, useCapture);
  76.                  }
  77.                  else if(obj.detachEvent){//  IE-style listeners?
  78.                     obj.detachEvent("on"+type,fn);
  79.                  }
  80.              }
  81.          }

  82.          //  Kill off the registry itself to get rid of the last remaining
  83.          //  references.
  84.          EventManager._registry = null ;
  85.     }
  86. };
复制代码


使用起来也很简单

  1.                                                                                                
  2. <html>
  3. <head>
  4. <script type=text/javascript src=EventManager.js></script>
  5. <script type=text/javascript>   
  6. function onLoad(){   
  7.    EventManager.Add(document.getElementById(testCase),click,hit);
  8.    return true;   
  9. }   

  10. function hit(evt) {        
  11.    alert(click);   
  12. }
  13. </script>
  14. </head>
  15. <body onload='javascript: onLoad();'>
  16. <div id='testCase' style='width:100%; height: 100%; background-color: yellow;'>  
  17. <h1>Click me!</h1>
  18. </div>
  19. </body>
  20. </html>
复制代码

                                                                               
google map api同样提供了一个类似的函数用在页面的unload事件中,解决Closure带来的内存泄露问题。

当然,如果你不嫌麻烦,你也可以为每个和native object有关的就阿vascript object编写一个destoryMemory函数,用来手动调用,从而手动解除Dom对象的事件绑定。

还有一种就是不要那么OO,抛弃Dom的一些特性,用innerHTML代替appendChild,避开循环引用。详细见http://birdshome.cnblogs.com/archive/2005/02/16/104967.html中的讨论贴。

Cross-Page Leaks

Cross-Page Leaks和下一节提到的Pseudo-Leaks在我看来,就是IE的bug,虽然MS死皮赖脸不承认

大家可以看看这段例子代码:

  1. <html>
  2. <head>
  3. <script language="JScript">
  4. // 这个函数会引发Cross-Page Leaks
  5. function LeakMemory()  
  6. {
  7.     var hostElement=document.getElementById("hostElement");

  8.     // Do it a lot, look at Task Manager for memory response

  9.     for (i=0 ;i<5000;i++){
  10.         var  parentDiv = document.createElement("<div onClick='foo()'>");
  11.         var  childDiv = document.createElement("<div onClick='foo()'>");

  12.         //  This will leak a temporary object
  13.         parentDiv.appendChild(childDiv);
  14.         hostElement.appendChild(parentDiv);
  15.         hostElement.removeChild(parentDiv);
  16.         parentDiv.removeChild(childDiv);
  17.         parentDiv = null ;
  18.         childDiv = null ;
  19.      }
  20.      hostElement = null ;
  21. }

  22. // 而这个函数不会引发Cross-Page Leaks
  23. function CleanMemory()   
  24. {
  25.       var hostElement = document.getElementById("hostElement");

  26.       //  Do it a lot, look at Task Manager for memory response

  27.       for (i=0;i<5000;i++)
  28.       {
  29.          var parentDiv = document.createElement("<div onClick='foo()'>");
  30.          var childDiv = document.createElement("<div onClick='foo()'>");

  31.          //  Changing the order is important, this won't leak
  32.          hostElement.appendChild(parentDiv);
  33.          parentDiv.appendChild(childDiv);
  34.          hostElement.removeChild(parentDiv);
  35.          parentDiv.removeChild(childDiv);
  36.          parentDiv = null ;
  37.          childDiv = null ;
  38.        }
  39.        hostElement  =   null ;
  40. }
  41. </script>
  42. </head>
  43. <body>
  44. <button onclick="LeakMemory()"> Memory Leaking Insert </button>
  45. <button onclick="CleanMemory()" > Clean Insert </button>
  46. <div id="hostElement"></ div >
  47. </body>
  48. </html>
复制代码


LeakMemory和CleanMemory这两段函数的唯一区别就在于他们的代码的循序,从代码上看,两段代码的逻辑都没有错。

但LeakMemory却会造成泄露。原因是LeakMemory()会先建立起parentDiv和childDiv之间的连接,这时候,为了让 childDiv能够获知parentDiv的信息,因此IE需要先建立一个临时的scope对象。而后parentDiv建立了和 hostElement对象的联系,parentDiv和childDiv直接使用页面document的scope。可惜的是,IE不会释放刚才那个临时的scope对象的内存空间,直到我们跳转页面,这块空间才能被释放。而CleanMemory函数不同,他先把parentDiv和 hostElement建立联系,而后再把childDiv和parentDiv建立联系,这个过程不需要单独建立临时的scope,只要直接使用页面 document的scope就可以了, 所以也就不会造成内存泄露了

详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。

IE 6中垃圾回收算法,就是从那些直接"in scope"的对象开始进行mark清除的:

Every variable which is "in scope" is called a "scavenger". A scavenger may refer to a number, an object, a string, whatever. We maintain a list of scavengers – variables are moved on to the scav list when they come into scope and off the scav list when they go out of scope.

Pseudo-Leaks

这个被称为“秀逗泄露”真是恰当啊^-^

看看这个例子:

  1. <html>
  2. <head>
  3. <script language="JScript">
  4. function LeakMemory()
  5. {
  6.     //  Do it a lot, look at Task Manager for memory response
  7.     for (i=0;i<5000;i++)
  8.     {
  9.         hostElement.text = "function foo(){}" ; // 看内存会不断增加
  10.     }
  11. }
  12. </script>
  13. </head>
  14. <body>
  15. <button onclick=" LeakMemory()"> Memory Leaking Insert </button>
  16. <script id="hostElement">function foo(){}</script>
  17. </body>
  18. </html>
复制代码


MS是这么解释的,这不是内存泄漏。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。在这里,您将创建许多元素,Internet Explorer 需要保存它们以正确呈现页面。Internet Explorer 并不知道您以后不会运行操纵您刚刚创建的所有这些对象的脚本。当页面消失时(当您浏览完,离开浏览器时)会释放内存。它不会泄漏。当销毁页面时,会中断循环引用。

唉~~~

详细原因,大家可以看看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp这篇文章。

其它一些琐碎的注意点:
■ 变量定义一定要用var,否则隐式声明出来的变量都是全局变量,不是局部变量;
■ 全局变量没用时记得要置null;
■ 注意正确使用delete,删除没用的一些函数属性;
■ 注意正确使用try...cache,确保去处无效引用的代码能被正确执行;
■ open出来的窗口即使close了,它的window对象还是存在的,要记得删除引用;
■ frame和iframe的情况和窗口的情况类似。

参考资料
http://jibbering.com/faq/faq_notes/closures.html
http://javascript.weblogsinc.com/2005/03/07/javascript-memory-leaks/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp
http://72.14.203.104/search?q=cache:V9Bt4_HBzQ8J:jgwebber.blogspot.com/2005/01/dhtml-leaks-like-sieve.html+DHTML+Leaks+Like+a+Sieve+&hl=zh-CN&ct=clnk&cd=9 (这是DHTML Leaks Like a Sieve)一文在google上的cache,原文已经连不上了)
http://spaces.msn.com/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!338.entry
http://support.microsoft.com/default.aspx?scid=KB;EN-US;830555
http://www.ajaxtopics.com/leakpatterns.html
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx
http://www.quirksmode.org/blog/archives/2005/02/javascript_memo.html
http://youngpup.net/2005/0221010713
http://blogs.msdn.com/ericlippert/archive/2003/09/17/53038.aspx =
http://support.microsoft.com/kb/266071/EN-US ==>IE 5.0至5.5一些版本中的GC bug
http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html ==>ie 7的改进
http://erik.eae.net/archives/2006/04/26/23.23.02/ ==>ie 7的改进
http://www.feedbackarchive.com/spamvampire/today.html ==> Try this script for memory leaks - it leaked 50 megabytes in 15 minutes with firefox on linux:
http://birdshome.cnblogs.com/archive/2005/02/15/104599.html
http://www.quirksmode.org/dom/innerhtml.html
http://www.crockford.com/javascript/memory/leak.html
《JavaScript: The Definitive Guide》4th Edition
http://outofhanwell.com/ieleak/index.php?title=Main_Page

[ 本帖最后由 caiying2007 于 2008-4-13 13:10 编辑 ]
西部数码顶级域名注册商39元抢注!

爵士乐

银牌会员

帖子
7325
体力
1270
威望
2
居住地
吉林省 四平市
发表于 2008-4-13 12:04:27 |显示全部楼层
好久没看到如此的好文了。
租服务器,上51IDC | [长沙]招聘:PHP经理10K/WEB前端6K/PHP开发6K

使用道具 举报

yaohaixiao 楼主

会武术的科学家

实习版主

帖子
2051
体力
5602
威望
45
居住地
浙江省 杭州市
发表于 2008-4-13 18:41:59 |显示全部楼层

回复 MywayLau 在 2# 的帖子

谢谢支持,不过这个文章对刚接触JAVASCRIPT的朋友,可能不太能看懂

使用道具 举报

skybot 

size

钻石会员 手机认证 

帖子
3236
体力
12466
威望
7
发表于 2008-4-14 10:03:15 |显示全部楼层
看得不是太懂.
http://www.qlili.com 个人站帮点啊

使用道具 举报

帖子
87
体力
355
威望
0
居住地
广东省 惠州市
发表于 2008-4-14 10:39:22 |显示全部楼层
內容不錯,也許更白話文一些會好點....
大头 --- bigik.cn

使用道具 举报

完全米撒了米

银牌会员 手机认证 

帖子
698
体力
1326
威望
0
发表于 2008-4-14 10:46:19 |显示全部楼层
强烈要求给LZ加精华!

使用道具 举报

赵勇

银牌会员 手机认证 

帖子
4121
体力
2375
威望
2
居住地
广东省 深圳市
发表于 2008-4-14 10:54:50 |显示全部楼层
关闭你的博客 少了4M内存占用 接着又增加了5m

使用道具 举报

小秦

版主 手机认证 

帖子
2886
体力
6713
威望
12
居住地
河南省 平顶山市
发表于 2008-4-14 16:07:09 |显示全部楼层
  1. 注意正确使用try...cache,确保去处无效引用的代码能被正确执行
复制代码



楼主英文不错...

使用道具 举报

yaohaixiao 楼主

会武术的科学家

实习版主

帖子
2051
体力
5602
威望
45
居住地
浙江省 杭州市
发表于 2008-4-15 06:32:43 |显示全部楼层

回复 faeng220 在 8# 的帖子

做这一行,英文还是要过得去的。

使用道具 举报

帖子
87
体力
355
威望
0
居住地
广东省 惠州市
发表于 2008-4-15 10:35:33 |显示全部楼层
原帖由 faeng220 于 2008-4-14 16:07 发表

注意正确使用try...cache,确保去处无效引用的代码能被正确执行

楼主英文不错...

原帖由 yaohaixiao 于 2008-4-15 06:32 发表
做这一行,英文还是要过得去的。


........
大头 --- bigik.cn

使用道具 举报

当当当

中级会员

帖子
209
体力
286
威望
4
发表于 2008-4-15 14:42:03 |显示全部楼层
他们俩故意幽默来着吧。
阿当

使用道具 举报

yaohaixiao 楼主

会武术的科学家

实习版主

帖子
2051
体力
5602
威望
45
居住地
浙江省 杭州市
发表于 2008-4-15 16:01:42 |显示全部楼层

回复 bigheadlyf 在 10# 的帖子

,呵呵,开心一刻,乱说一下,不要那么严肃啊,谁都有打错字的时候啊

[ 本帖最后由 yaohaixiao 于 2008-4-15 16:03 编辑 ]

使用道具 举报

zcfg 
帖子
169
体力
341
威望
5
发表于 2008-4-15 17:19:50 |显示全部楼层
好文收藏。十分感谢楼主的分享,不过有些例子没看明白,有点晦涩。
顺便说一下,在Cross-Page Leaks的例子中,第一个例子创建dom元素的顺序在现代浏览器中应该是比较推崇的吧?因为向文档中执行append操作的次数要少一半。

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

Archiver|手机版|安久科技提供CDN|blueidea.com ( 京ICP备05002321号 )  

GMT+8, 2012-2-13 11:06 , Processed in 0.110579 second(s), 8 queries , Gzip On, Memcache On.

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部