浅谈 Javascript 性能优化

7,978 views

Published on

improve javascript performance

Published in: Self Improvement
4 Comments
19 Likes
Statistics
Notes
No Downloads
Views
Total views
7,978
On SlideShare
0
From Embeds
0
Number of Embeds
41
Actions
Shares
0
Downloads
220
Comments
4
Likes
19
Embeds 0
No embeds

No notes for slide

浅谈 Javascript 性能优化

  1. 1. 浅谈 JavaScript 性能优化<br />龙刚 (@RainoXu)TaobaoUED<br />www.rainoxu.com<br />
  2. 2. 优化 JavaScript性能,使它运行足够快一个关键因素:运行的时间<br />
  3. 3. 响应时间与用户的体验<br />0.1s<br />用户觉得很流畅<br />1.0s<br />用户的操作可能偶尔受到影响,并且用户已经能感觉到有些不流畅<br />10s<br />对用户的影响比较严重,需要相应的进度提示。用户也会有一些沮丧<br />
  4. 4. What To Do && How To Do?<br />
  5. 5. 管理作用域<br />操作数据<br />流控制<br />Reflow<br />DOM操作<br />长时间运行的脚本处理<br />
  6. 6. 管理作用域<br />function add(num1, num2){<br />return num1 + num2; <br />} <br />var result = add(5, 10);<br />
  7. 7. 使用局部变量<br />局部变量存在于活动对象中,解析器只需查找作用域中的单个对象<br />var a = 1;<br />function test(){<br /> //对变量a进行一系列操作<br />}<br />function test2(){<br />var a = 1;<br /> //对变量a进行一系列操作<br />}<br />
  8. 8. 另一个例子<br />(function(win, S, undefined) {<br /> ...<br /> ...<br />var doc = win['document'], loc = location,<br /> EMPTY = '',<br /> ...<br /> ...<br />})(window, 'KISSY');<br />
  9. 9. 数据操作<br />
  10. 10. 使用局部变量,它是最快的缓存频繁使用的对象、数组及相关的属性值<br />
  11. 11. obj.name比obj.xxx.name访问更快,访问属性的速度,与其在对象中的深度有关<br />“ . ”操作的次数直接影响着访问对象属性的耗时<br />varobjName = obj.name;<br />
  12. 12. KISSY.add('switchable', function(S, undefined) {<br />var DOM = S.DOM, Event = S.Event,<br /> ...<br /> ...<br />});<br />
  13. 13. function process(data){<br /> if (data. count> 0){<br /> for(vari = 0; i < data.count; i++){<br />processData(data.item[i]);<br /> } <br /> }<br />}<br />
  14. 14. function process(data){<br />var count = data.count;<br /> if (count > 0){<br /> for(vari = 0; i < count ; i++){<br />processData(data.item[i]);<br /> } <br /> }<br />}<br />
  15. 15. NodeList<br />不直接操作NodeList,将其转换成静态数组后再使用<br />方法:<br />Array.prototype.slice.call() => 标准浏览器<br />逐个拷贝到一个新数组中 => For IE<br />
  16. 16. 大部分JS库都有提供将Array-Like的对象转变成Array的方法(如KISSY提供的makeArray()方法);部分JS库在返回元素集合时,已预处理成Array(例子:YUI的DOM相关操作方法)<br />
  17. 17. 遍历NodeList时,不做对当前NodeList相关结构有影响的DOM操作,并且如之前所提到的,要缓存一些频繁使用到的属性值,以避免杯具发生。<br />
  18. 18. vardivs = document.getElementsByTagName('DIV');<br /> //假定页面中有div,所以divs.length是大于0的<br />for (varidx = 0; idx < divs.length; idx++){<br />document.body.appendChild(<br />//杯具悄然而置<br />document.createElement('DIV')<br /> );<br /> console.info(divs.length);<br /> }<br />
  19. 19. 杯具的原因?<br />通过getElementsByTagName()获取得到的是一个LiveNodeList的引用,任何对其相关的DOM操作都会立即反应在这个NodeList上面<br />通过不断地往document.body下插入div 节点,for循环的终止条件(div.length也随之改变)失效,陷入死循环。<br />
  20. 20. Live NodeListvs Static NodeList<br />理论上,静态的东西应该是最快的,但是实际情况是,Live NodeList更快。<br />
  21. 21. Live NodeListvs Static NodeList<br />原因:目前市场上的浏览器,对Live NodeList做了缓存<br />
  22. 22. Live NodeListvs Static NodeList<br />结论:优先使用Live NodeList,通过选择器获取以后,再进一步转换成数组来使用。这也是目前许多JS库在使用的方案。<br />
  23. 23. DOM操作<br />指明操作DOM的context<br />YUI:<br /> Array getElementsByClassName ( className , tag , root , apply , o , overrides ) <br />KISSY:<br /> Array<HTMLElement> query ( selector, context )<br />即便是用原生的JS,也应该指明:<br />context.getElementsByTagName()<br />
  24. 24. DOM操作<br />增删、修改节点<br />使用DocumentFragment<br />使用cloneNode()复制一份目标节点来处理<br />如果是直接修改DOM,请先将其display:none;<br />
  25. 25. 一个方法尽可能只做一件事<br />拆分功能,让一个方法只做一件事,通过不断地调用方法来实现复杂功能,但是,这些简单方法要避免相互交叉调用。<br />
  26. 26. KISSY Poster中的一些方法拆分<br />
  27. 27. KISSY Poster中的一些方法拆分<br />
  28. 28. Be Lazy<br />使脚本尽可能少地运行,或者不运行。<br />
  29. 29. 短路表达式应用:如 a && b || c<br />基于事件去写相应的处理方法<br />惰性函数<br />
  30. 30. 合理地使用事件代理<br />DOM与事件处理<br />
  31. 31. 为元素绑定事件<br />Event.on ( target, type, fn, scope )<br />
  32. 32. 事件代理的原理<br />冒泡<br />捕获<br />
  33. 33. 事件代理应用的场景?<br />
  34. 34.
  35. 35. Event.on(container, ‘click’, function (ev){<br />var target = ev.target();<br /> switch(target.className){//或者可以是nodeName<br /> ...<br /> ...<br /> ...<br /> }<br />});<br />
  36. 36. 流控制<br />
  37. 37. if(...){<br />}elseif(...){<br />}elseif(...){<br />}elseif(...){<br />}elseif(...){<br />}elseif(...){<br />}else{<br />}<br />
  38. 38. 在if语句中,将经常会发生的条件,放在靠上的位置<br /> if的条件为连续的区间时,可以使用二分法的方式来拆分<br />较多离散值的判断,可以使用switch来替代<br />使用数组查询的方式<br />
  39. 39. 要注意隐式的类型转换<br />varfoo = 0;<br /> if(foo == false){<br /> ...<br /> }<br />
  40. 40. 小心递归!<br />
  41. 41. function recurse(){<br />recurse();<br />}<br />recurse();//又是一个杯具<br />
  42. 42. 浏览器对调用栈的最大限度的定义各不一样<br />递归的相互调用、自身调用可能触发浏览器的调用栈的最大极限<br />
  43. 43. Reflow<br />
  44. 44. 主要引起Reflow的因素<br />操作DOM树<br />与布局有关的样式改变<br />改变className<br />窗口大小调整<br />字休大小<br />
  45. 45. 优化运行时间较长的脚本<br />
  46. 46. 原因:<br />大量DOM操作<br />过多的循环与递归<br />解决问题的最佳实践:<br />使用定时器<br />
  47. 47. 最后,优化原则?<br />
  48. 48. 2/8原则<br />考虑大多数情况,极端情况,有能力则兼顾之,适当取舍<br />
  49. 49. 性能与可维护性权衡之一原则<br />
  50. 50. 站在巨人的肩膀上,看得更远<br />YAHOO的前端小组、JohnResig、NicholasC.Zakas等都已经总结了很多有用的性能优化方面的经验,以他们的研究成果做为优化时的参考。<br />
  51. 51. 好的编程习惯<br /><ul><li>不以善小而不为
  52. 52. 思先于行,不必过早优化</li></li></ul><li>最后,感谢玉伯、云谦、圆心、龙俊、释然对我此次的分享提供了许多帮助和建议。<br />
  53. 53. Question?<br />

×