高性能Javascript
Upcoming SlideShare
Loading in...5
×
 

高性能Javascript

on

  • 905 views

 

Statistics

Views

Total Views
905
Views on SlideShare
905
Embed Views
0

Actions

Likes
0
Downloads
55
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

高性能Javascript 高性能Javascript Presentation Transcript

  • High  Performance  JavaScript 2011-09-0911年9月13日星期二
  • About  Me 谢传贵(阿贵) 前端开发部-前端架构组 新浪微薄@十月光风11年9月13日星期二
  • 11年9月13日星期二
  • 先来看一场微电影,时长6.5s11年9月13日星期二
  • 0s11年9月13日星期二
  • 0.5s11年9月13日星期二
  • 1.0s11年9月13日星期二
  • 1.5s11年9月13日星期二
  • 2.0s11年9月13日星期二
  • 2.5s11年9月13日星期二
  • 3.0s11年9月13日星期二
  • 3.5s11年9月13日星期二
  • 4.0s11年9月13日星期二
  • 4.5s11年9月13日星期二
  • 5.0s11年9月13日星期二
  • 5.5s11年9月13日星期二
  • 6.0s11年9月13日星期二
  • 6.5s11年9月13日星期二
  • 回顾 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.511年9月13日星期二
  • 知己知彼,百战不殆11年9月13日星期二
  • Topic JavaScript运行过程 快速响应UI 更多编程实践 效率相关的工具11年9月13日星期二
  • JavaScript运行的过程是怎么样的?11年9月13日星期二
  • 从源码到可执行代码 解释 编译 (interpreted) (compiled)11年9月13日星期二
  • (function(){ source.js(源码) alert(‘hello  world’) }) 编译 helloworld.exe 0100100101010101 (二进制码) 执行 运行时环境 Runtime.exec(‘hello.exe’) 编译11年9月13日星期二
  • (function(){ source.js(源码) alert(‘hello  world’) }) helloworld.exe 编译&运行 (二进制码) 运行时环境 Runtime.exec(‘hello.exe’) 解释11年9月13日星期二
  • (function(){ alert(‘hello  world’) }) 编译&运行 Runtime.exec(‘中间机器解释器执行伪代码 运行时环境(浏览器) 解释11年9月13日星期二
  • (function(){ alert(‘hello  world’) }) JavaScript  Engine 编译&运行 Runtime.exec(‘中间机器 运行时环境(浏览器) 解释11年9月13日星期二
  • JavaScript  是解释型语言11年9月13日星期二
  • JavaScript代码执行的过程 词法分析 语法检查 语法分析 预编译 运行时 运行11年9月13日星期二
  • JavaScript代码执行的过程 词法分析 语法检查 语法分析 将上下文中var申明  的变量放 入”栈”中  并赋值为undefined 预编译 读入”定义”的函数 运行时 运行11年9月13日星期二
  • 看个例子11年9月13日星期二
  • (function(){ alert(a);  //  会报错么? if(false){ var  a=1;   } })();11年9月13日星期二
  • 函数执行前,函数内部变量均被声明 (function(){ alert(a);  //  显示undefined,不报错 if(false){ var  a=1;  //不会执行到,亦被声明 } })();11年9月13日星期二
  • 再来看个例子11年9月13日星期二
  • test(); function  test(){   alert(1); } test(); function  test(){   alert(2); } test(); var  test  =  function(){   alert(3); } test(); test  =  function(){   alert(4); } test();11年9月13日星期二
  • test(); function  test(){//预编译定义,运行时略过   alert(1); } test(); function  test(){//预编译定义,运行时略过   alert(2); } test(); var  test  =  function(){//预编译声明,运行时赋值   alert(3); } test(); test  =  function(){//运行时,变量赋值   alert(4); } test();11年9月13日星期二
  • JavaScript性能会影响到用户体验吗?11年9月13日星期二
  • JavaScript  性能已经直接影响到用户体验11年9月13日星期二
  • JavaScript  is  Slow!11年9月13日星期二
  • 11年9月13日星期二
  • 11年9月13日星期二
  • JavaScript  is  Fast!11年9月13日星期二
  • JavaScript引擎 V8  C++ JaegerMonkey  C++ JScript  JSctipt.Net Nitro  C++ Karakan  C++ ...11年9月13日星期二
  • JavaScript运行越来越快 http://ie.microsoft.com/testdrive/benchmarks/sunspider/default.html11年9月13日星期二
  • IE8 IE6 Sougou IE7 IE9 Tt Chrome Maxyhon Firefox Theworld Se360 Other Opera Safari http://www.1688.com/11年9月13日星期二
  • IE8 IE6 Sougou IE7 IE9 Tt Chrome Maxyhon Firefox Theworld Se360 Other Opera Safari 0.13% 0.10% 0.37% 0.96% 0.99% 1.11% 1.17% 1.24% 1.67% 3.09% 3.74% Sougou IE8 5.03% 40.60% IE6 39.81% http://www.1688.com/11年9月13日星期二
  • 但如果不了解,不注意,依然有可能 写出非常低效(Inefficient)的JavaScript代码11年9月13日星期二
  • Douglas  Crockford Steve  Sounders Nicholas.C.Zakes 大牛11年9月13日星期二
  • UI线程11年9月13日星期二
  • 浏览器是如何渲染的? Input ? output <!DOCTYPE  html> <html> <head> <title>1688首页</title> </head> <body> <div>hello</div> <script> doc.write(‘helloworld’); </script> <div>world</div> </body> </html>11年9月13日星期二
  • 浏览器渲染过程 Fetch Parse Flow Paint Display URL Cache Tree Pixels List http://technotes-himanshu.blogspot.com/2010/05/html-dom.html11年9月13日星期二
  • 执行脚本过程中的渲染 Flow Paint Script Event11年9月13日星期二
  • JS执行和浏览器渲染11年9月13日星期二
  • 构建DOM 树 document <!DOCTYPE html> <html> <head> head <title>1688首页</title> </head> title <body> <div id=”a”>hello</div> body <script> doc.write(‘helloworld’); div </script> <div id=”b”>world</div> script </body> JS引擎创建了 </html> textNode textNode div11年9月13日星期二
  • 阻塞: JS运行会中断HTML的渲染11年9月13日星期二
  • 浏览器是单线程作业 同一时刻只能做一件事情,要么是用户界面更新,要么是JavaScript脚本执行11年9月13日星期二
  • 在UI线程忙碌的情况下,UI更新和JS执行都会被加入UI队列里, 直到当前任务执行完毕,才会被激活11年9月13日星期二
  • time UI  Rendering  Thread 2.更新  UI DOM 1.构建DOM11年9月13日星期二
  • time UI  Rendering  Thread UI  Update 渲染出此时的DOM DOM11年9月13日星期二
  • time UI  Rendering  Thread UI  Update Exec  JS 3.JS  脚本新增DOM节点 DOM11年9月13日星期二
  • time UI  RenderingThread UI  Update Exec  JS UI  Update 4.更新UI DOM11年9月13日星期二
  • JavaScript执行时间  =  UI不可响应时间11年9月13日星期二
  • UI可响应的 UI  Update Exec  JS UI  Update time11年9月13日星期二
  • UI不可响应的 UI  Update Exec  JS UI  Update time 假死11年9月13日星期二
  • JavaScript执行过程耗时越久, 浏览器等待响应用户输入的时间就越长, 就有多不好的用户体验11年9月13日星期二
  • 浏览器对于JavaScript运行的限制 主要分为两类: 1.调用栈大小限制 2.长时间运行限制11年9月13日星期二
  •   ,  11年9月13日星期二
  • - 11年9月13日星期二
  • 浏览器限制 IE:500万条语句 Firefox:10秒 Safari:5秒 Chrome:没有单独的长运行脚本限制,替代做法是依赖 于其崩溃检测系统来处理此类问题 Opera:没有长运行脚本限制11年9月13日星期二
  • 多久才算太久?11年9月13日星期二
  • 如果JavaScript运行了整整几秒 钟,那么很可能你做错了什么.... --Brendan  Eich11年9月13日星期二
  • 在100毫秒以内响应用户输 入,用户会认为自己在直接操 作界面中的对象.超过100毫 秒意味着用户会感到自己与 界面失去联系. --  Jokob  Nielsen11年9月13日星期二
  • 最佳实践:少于50毫秒11年9月13日星期二
  • JavaScript Load最佳实践11年9月13日星期二
  • 浏览器在进行JavaScript下载,解析和运行 都是会阻塞页面渲染的?11年9月13日星期二
  • <!DOCTYPE html> <html> <head> <title>1688首页</title> </head> <body> <div>hello</div> <script src=”jQuery.js”></script> <div>world</div> </body> </html>11年9月13日星期二
  • 结果 UI  Update JavaScript UI  Update11年9月13日星期二
  • 结果 UI  Update jQuery.js UI  Update11年9月13日星期二
  • 结果 UI  Update download parse run UI  Update11年9月13日星期二
  • <!DOCTYPE html> <html> <head> <title>1688首页</title> </head> <body> <div>hello</div> <script src=”jQuery.js”></script> <div>world</div> <script src=”yui2.js”></script> <div>1688</div> <script src=”yui3.js”></script> </body> </html>11年9月13日星期二
  • 结果 UI  Update JavaScript UI  Update JavaScript UI  Update JavaScript11年9月13日星期二
  • JavaScript Load最佳实践1:把JS放到页面底部11年9月13日星期二
  • 11年9月13日星期二
  • 结果 UI  Update UI  Update UI  Update JavaScript JavaScript JavaScript11年9月13日星期二
  • <!DOCTYPE html> <html> <head> <title>1688首页</title> </head> <body> <div>hello</div> <div>world</div> <div>1688</div> <script src=”jQuery.js”></script> <script src=”yui2.js”></script> <script src=”yui3.js”></script> </body> </html>11年9月13日星期二
  • JavaScript Load最佳实践2:JS合并11年9月13日星期二
  • <!DOCTYPE html> <html> <head> <title>1688首页</title> </head> <body> <div>hello</div> <div>world</div> <div>1688</div> <script src=”jQuery-yui2-yui3.js”></script> </body> </html>11年9月13日星期二
  • 结果 UI  Update UI  Update UI  Update JavaScript11年9月13日星期二
  • 当然我们可以通过工具来完成自动合并11年9月13日星期二
  • 独角兽 Google  Page  Speed  Module ...11年9月13日星期二
  • JavaScript Load最佳实践3:无阻塞异步加载JS11年9月13日星期二
  • 可选方案 Script DOM Element Script Defer Script Async Iframed JS XML HttpRequest Script Injection11年9月13日星期二
  • Script DOM Element原理 var script = document.createElement("script") body = document.body; script.type = "text/javascript"; script.src = "foo.js"; body.insertBefore(script, body.firstChild);11年9月13日星期二
  • 结果 UI  Update run UI  Update Time download parse11年9月13日星期二
  • 类库选择 YUI2(YAHOO.util.Get.script) jQuery( jQuery.ajax) LABjs headjs requirejs SeaJs ...11年9月13日星期二
  • Script  Defer <script  defer  src="foo.js"></script>11年9月13日星期二
  • 浏览器支持情况 7.0 3.5 4.0 ? 5.011年9月13日星期二
  • Script  Async <script  async  src="foo.js"></script>11年9月13日星期二
  • 浏览器支持情况 7.0 3.5 ? ? 5.011年9月13日星期二
  • Iframed  JS function  iframedJS(s){   document.write("<iframe  id=  i></iframe>");   var  d  =   document.getElementById("i").contentWindow.docum t;   d.write(<!doctype  html><html><body><scr  +  ipt   src="+s +"></scr  +  ipt></body></html>);   window.setTimeout((function(){d.close();}),0); }11年9月13日星期二
  • 缺点 对同一个iframe多次进行doc.open+write+close,会 增加浏览历史记录 Firefox  doc.write  iframe至页面,可能不能马上取到其 引用 domain的潜在问题11年9月13日星期二
  • XML  HttpRequest  Script  Injection var  xhr  =  new  XMLHttpRequest(); xhr.open(‘get’,‘file.js’,true); xhr.onreadystatechange=function(){ if(xhr.staus==4){ if(xhr.status>=200&&  xhr.status<300||  xhr.status==304){ var  script  =  document.createElemet(‘script’); script.type=  ‘text/javascript’; script.text  =  xhr.responseText; document.body.appendChild(script); } } }11年9月13日星期二
  • 特点 可先下载,但不立即执行 主流浏览器都支持 有同域的要求11年9月13日星期二
  • JavaScript  Compression  最佳实践11年9月13日星期二
  • JavaScript  Compression  最佳实践1.上线前压缩11年9月13日星期二
  • 可选工具 YUI  Compressor Google    Closure  Compiler UglifyJS Packer ...11年9月13日星期二
  • JavaScript  Compression  最佳实践2.网络传输压缩11年9月13日星期二
  • 可选方案 gzip compress deflate identity11年9月13日星期二
  • JavaScript  Exec  最佳实践11年9月13日星期二
  • JavaScript  Exec  最佳实践  1:使用定时器让出时间片11年9月13日星期二
  • UI  Thread UI  Update-Button JavaScript-click JavaScript-click UI  Queue JavaScript-click UI  Update-Button Timer  coder JavaScript-click 0 50 setTimeout() called Timer code queued11年9月13日星期二
  • 使用定时器处理数组 var  todo  =  items.concat(); setTime(function(){ //取得数组的下个元素进行处理 process(todo.shift()); if(todo.length  >  0){ setTimeout(arguments.callee,25); }  else  { callback(items); } },25);11年9月13日星期二
  • 分割任务 function  multistep(steps,args,callback){ var  tasks  =  steps.concat(); setTimeout(function(){ var  task  =  tasks.shitf(); task.apply(null,args  ||  []); if(tasks.length  >  0){ setTimeout(arguments.callee,25); }else{ callback(); }11年9月13日星期二 },25);
  • JavaScript  Exec  最佳实践  2:Web  Workers11年9月13日星期二
  • 11年9月13日星期二
  • Web  Workers  没有绑定UI线程11年9月13日星期二
  • //in  page var  worker  =  new  Worker("process.js");   worker.onmessage  =  function(event){ useData(event.data); worker.postMessage(values); }; //in  process.js self.onmessage  =  function(event){   var  items  =  event.data;   for  (var  i=0,len=items.length;  i  <  len;  i++){ }; process(items[i]);   self.postMessage(items); }11年9月13日星期二
  • 使用场景 编码/解码大字符串 复杂数学运算 大数组排序11年9月13日星期二
  • 浏览器支持情况 7.0 3.5 ? 10.6 4.011年9月13日星期二
  • DOM编程11年9月13日星期二
  • 天生就慢 ECAM  Land DOM  Land ECMA每次访问DOM,都需要途经这座桥,并交纳”过桥费”.访问的次数越多,费用就越高11年9月13日星期二
  • 代价很昂贵 function  innerHTMLLoop(){ for(var  count=0;count<1000;i++){ document.getElementById(‘i’).innerHTML +=”a”; } }11年9月13日星期二
  • 优化后 function  innerHTMLLoop(){ var  content=[]; for(var  count=0;count<1000;i++){ content.push(‘a’); } document.getElementById(‘i’).innerHTML  =   content.join(‘’); }11年9月13日星期二
  • 比较 innerHTML,createElement,cloneNode 案例:http://blog.stevenlevithan.com/archives/faster-than-innerhtml http://stevenlevithan.com/demo/replaceHtml.html11年9月13日星期二
  • 重绘和重排11年9月13日星期二
  • UI  Update时间  =  UI不可用时间11年9月13日星期二
  • <button  id="btn"  style="font-size:  30px;">Click  Me</ button> <script  type="text/javascript">   window.onload  =  function(){ document.getElementById("btn").onclick  =  function() var  div  =  document.createElement(“div”);   div.className  =  “tip”;   div.innerHTML  =  “You  clicked  me!”;   document.body.appendChild(div); };   } </script>11年9月13日星期二
  • JavaScript执行会触发重绘和重排会导致 长时间UI  Update11年9月13日星期二
  • 浏览器渲染11年9月13日星期二
  • 重绘何时发生? visibility 颜色 背景图片 不会触发layout改变11年9月13日星期二
  • 重排何时发生? 添加或删除可见的DOM节点 元素位置改变 元素尺寸改变(包括:外边框,内边距,边框厚度,宽度,高度 等属性改变) 页面渲染器初始化 浏览器窗口尺寸改变 页面布局+几何属性改变都会触发重排11年9月13日星期二
  • 重绘 <button  id="btn">Click  Me</button> <script  type="text/javascript">   window.onload  =  function(){ document.getElementById("btn").onclick  =  function(){   this.style.color  =  "#ff0"; } 重绘 };   </script>11年9月13日星期二
  • 重排 <button  id="btn"  style="font-size:  30px;">Click  Me</button> <script  type="text/javascript">   window.onload  =  function(){ document.getElementById("btn").onclick  =  function(){   var  div  =  document.createElement(“div”);   div.className  =  “tip”;   div.innerHTML  =  “You  clicked  me!”;   document.body.appendChild(div); };   重排 } </script>11年9月13日星期二
  • 最小化重绘和重排11年9月13日星期二
  • 方法 批量修改样式,采用cssTest或者改变className的方式 批量修改DOM,使DOM脱离文档 缓存布局信息 让元素脱离动画流 事件委托 ...11年9月13日星期二
  • 批量修改样式 var el = document.createElementById(‘mydiv’); el.style.borderLeft = ”1px”; 重绘 el.style.borderRight = ‘2px’; el.style.padding = ‘5px’; 重绘 重绘 3次重绘11年9月13日星期二
  • 优化后 var el = document.createElementById(‘mydiv’); el.style.cssText = ‘border-left:1px;border-right:2px; padding:5px;’; 1次重绘11年9月13日星期二
  • 还可以这么做 var el = document.createElementById(‘mydiv’); el.className = ‘active’; 1次重绘11年9月13日星期二
  • 使DOM脱离文档 隐藏元素,应用修改,重新显示 使用文档片段(document  fragment)在当前DOM之外 构造一个子树,在把它拷回文档 将原始元素拷贝到一个脱离文档的节点中,修改副本,完 成后再替换原始元素11年9月13日星期二
  • 1.隐藏元素 var  ul  =  document.getElementById(‘myList’); ul.style.display  =  ‘none’; appendDataToElement(ul,data); ul.style.display  =  ‘block’;11年9月13日星期二
  • 文档片段 var  fragment  =  document.createDocmentFragment(); appendDataToElement(fragment,data); document.getElementById(‘myList’).appendChild(‘f ragment’)11年9月13日星期二
  • 缓存布局信息 myElement.style.left  =  1+myElement.offsetLeft +’px’; if(myElement.offsetLeft>500){ stopAnimation(); } 非常的低效11年9月13日星期二
  • 可以这么优化 current++ myElement.style.left  =  current+’px’; if(myElement.offsetLeft>500){ stopAnimation(); }11年9月13日星期二
  • 让元素脱离动画流 使用绝对位置定位页面上的元素,将其脱离文档流 让元素动起来.当它扩大时,会临时覆盖部分页面.这个时 候只会小区域的重绘 当动画结束时恢复定位,从而知会下移一次文档的其他 位置11年9月13日星期二
  • 事件委托 场景:当页面中存在大量元素,而且每⼀一个都要⼀一次 或多次绑定事件处理器.11年9月13日星期二
  • 事件委托 结果是可能会影响性能.每绑定一个事件处理器 都是有代价的,它要么加重了页面负担.,要么增加 了运行期的执行时间.需要访问和修改的DOM元 素越多,  应用程序也就越慢.11年9月13日星期二
  • 解决方案 事件冒泡 例:YAHOO.util.Event.delegate http://developer.yahoo.com/yui/event/11年9月13日星期二
  • 更多编程实践 更高效的代码(条件预加载,延迟加载,位操作等) 正则表达式优化(例:Detail详情延迟加载) 数据缓存(JS对象缓存,Ajax数据缓存等) GC和避免内存泄漏( http://www.aliued.cn/2010/09/19/gc-and-js-memory-leak.html ) CSS3动画 其他见(Extreme  JavaScript  Performance.pdf)11年9月13日星期二
  • 工具 JS执行效率测试工具 内存泄漏检测工具 ...11年9月13日星期二
  • F  谢谢11年9月13日星期二