Your SlideShare is downloading. ×
0
从无阻塞脚本加载 (LAB.js) 到浏览器线程模型 Jackson Tian/ 田永强  @ 朴灵  at SAP 05/09/11
Agenda <ul><li>为什么 script 会阻塞页面解析 </li></ul><ul><li>如何实现无阻塞脚本加载 </li></ul><ul><li>依赖管理与无阻塞并行加载与顺序执行 (LAB.js 实现机制 ) </li></...
说到无阻塞脚本加载 <ul><li>你不得不知道的大牛是 </li></ul><ul><li>Steve Souders </li></ul><ul><li>At  Google  on web performance and open sou...
为什么 script 标签会阻塞页面解析 05/09/11
05/09/11
Document.write 是魔鬼   <ul><li>队列的基本原则 </li></ul><ul><ul><li>先进先出原则( FIFO, First-In-First-Out ) http://zh.wikipedia.org/wiki...
05/09/11
Alert 也是魔鬼 <ul><li>alert(“I am evil, too.”); </li></ul><ul><li>是否有人通过 alert 来 debug JavaScript 程序呢? </li></ul><ul><ul><li>...
为什么 script 标签会阻塞页面解析 <ul><li>基于以上的历史原因, JavaScript 线程与 UI 共用同一进程,而且 JS 任务优先于 UI 任务 </li></ul><ul><li>浏览器会在遇到 Script 标签的时候进...
Chromium 解析流程 05/09/11 此图由 Tapir( 貘 ) 提供,感谢他
YSlow 的 35 条军规 <ul><ul><li>Put Scripts at the Bottom </li></ul></ul><ul><ul><ul><li>http://developer.yahoo.com/performance...
无阻塞脚本加载 05/09/11
Defer 属性 <ul><li>HTML4 标准为 <script> 标签定义了 defer 属性,以此声明告诉浏览器内容中不包含 document.write 之类破坏 DOM 的脚本 </li></ul><ul><li>浏览器会延迟(无阻...
Async 属性 <ul><li>HTML5 标准为 <script> 标签定义了 async 属性 </li></ul><ul><li>与 defer 属性相同的是脚本会无阻塞加载 </li></ul><ul><li>与 defer 属性不同...
标准与实现之间的差距 <ul><li>动态脚本元素 </li></ul><ul><ul><li>利用一小段脚本去创建 <script> 标签,实现无阻塞加载 </li></ul></ul><ul><ul><li>var script = doc...
Script 标签的 onload 事件 <ul><li>  function loadScript(url, callback){ </li></ul><ul><li>     var script = document.createElem...
无阻塞脚本加载实例 <ul><li>Google Analytics 代码 </li></ul><ul><ul><li>http://code.google.com/intl/zh-CN/apis/analytics/docs/tracking...
XMLHttprequest 脚本注入 <ul><li>$.get(“script.js”, function (responseText) { var script = document.createElement(“script”); sc...
XMLHttpRequest   Eval <ul><li>$.get(“script.js”, function (responseText) { eval(responseText); }); </li></ul><ul><li>与 XML...
document.write Script Tag <ul><li>  document.write(“<script src=‘script.js’> </script>”); </li></ul><ul><li>只有 IE 生效 </li>...
Script in Iframe <ul><li>我也不知道怎么搞。 </li></ul><ul><li>很复杂。 </li></ul><ul><li>Google 都 Google 不到。 </li></ul><ul><li>也许是 <ifr...
问题总结 <ul><li>同源策略限制 (XHR inject, XHR eval,Iframe) </li></ul><ul><li>顺序执行 ( 动态 script 元素 , async) </li></ul><ul><li>浏览器支持 (...
各种方法支持一览 05/09/11 方法 并行加载 顺序执行 不受同源限制 浏览器都支持 Defer √ √ √ x Async √ x √ x 动态脚本元素 √ x √ √ XHR Inject √ √ x √ XHR Eval √ √ x ...
无顺序执行的要求情况下 05/09/11 方法 并行加载 顺序执行 不受同源限制 浏览器都支持 Defer √ √ √ x Async √ x √ x 动态脚本元素 √ x √ √ XHR Inject √ √ x √ XHR Eval √ √...
05/09/11
如何控制依赖加载 <ul><li>通过 onload 事件控制? loadScript(“file1.js”, function() {   loadScript(“file2.js”, function() {   loadScript(“f...
如何控制依赖加载 <ul><li>或者采用 defer ? <script src=“script1.js” defer></script>  <script src=“script2.js” defer></script>  <script ...
如何控制依赖加载 <ul><li>更或者通过 XHR 动态加载,顺序执行 </li></ul><ul><li>同源策略怎么办? </li></ul>05/09/11
如何控制依赖加载 <ul><li>在 Server 端组织好脚本顺序,并且 combo 成一个文件 </li></ul><ul><li>这是一个好主意!!! </li></ul><ul><li>但是总有你不能 combo 的文件,比如本地化的资...
<ul><li>依赖加载  ≠ 必须顺序加载  ≠ 串行加载 </li></ul>05/09/11
<ul><li>顺序执行 ≠ 立即执行 </li></ul>05/09/11
有没有一种方法 <ul><li>能实现并行下载 </li></ul><ul><li>能实现顺序执行 </li></ul><ul><li>能没有副作用 </li></ul>05/09/11
LAB.js <ul><li>@getify </li></ul><ul><li>Kyle Simpson </li></ul><ul><li>公司: Getify Solutions </li></ul><ul><li>LABjs 被很多大网...
LABjs 的诀窍 <ul><li>对于 Firefox/Opera ,采用动态 Script DOM element 可以完美地实现并行下载和顺序执行 </li></ul><ul><li>对于 Safari/Chrome ,无法保证顺序执行,...
<ul><li>在需要的文件下载完成之后,再次通过插入正确的 type=“text/javascript” 而且监听 onload 来完成对于顺序执行的控制 </li></ul><ul><li>LABjs 判断 script 文件是否同域文件,...
LABjs 示例 <ul><li>Sample Code </li></ul><ul><ul><li><script src=&quot;LAB.js&quot;></script>  <script> $LAB .script(&quot;h...
LABjs 方法 <ul><li>主要方法 </li></ul><ul><ul><li>Script() </li></ul></ul><ul><ul><ul><li>可以多次调用 script 方法来并行加载脚本 </li></ul></ul...
LABjs API 示意 05/09/11
题外话 <ul><li>曾经 Firefox4 试图改掉动态脚本元素按顺序执行的特性,使得像 Chrome/Safari 一样 </li></ul><ul><li>那么,在面对 CDN 脚本, text/cache 失效的情况下, LABjs ...
题外话 <ul><li>后来, getify 赢了 </li></ul>05/09/11
无阻塞脚本与 DOM <ul><li>在脚本加载完成的时候, DOM 可能 </li></ul><ul><ul><li>DOM 还没有 DOMContentLoaded( 加载速度快或者来自 cache) </li></ul></ul><ul>...
如何解决以上问题? <ul><li>DOM 还没有 DOMContentLoaded( 加载速度快或者来自 cache) </li></ul><ul><ul><li>保证 DOM 操作注册在 DOMContentLoaded 事件中 </li>...
回顾 <ul><li>Combo 脚本文件,以减少链接数 </li></ul><ul><li>优先加载和无阻塞加载,实现界面快速响应 </li></ul><ul><li>采用 LABjs 做依赖管理,实现并行下载和顺序执行 </li></ul>...
为什么要啰嗦浏览器线程 <ul><li>无阻塞加载讲得又不深入,还要啰嗦浏览器线程 </li></ul><ul><li>因为扯谈了这么多,目的只是将脚本的下载线程脱离 UI 线程而已 </li></ul><ul><li>设计 JavaScrip...
<ul><li>为什么 JavaScript 作为一门编程语言,却没有多线程? </li></ul><ul><li>抱怨 JavaScript 没有多线程的程序员不是好程序员 </li></ul><ul><li>有多少人用 setTimeout...
JavaScript 线程 <ul><li>JavaScript 的多线程 </li></ul><ul><ul><li>找到约  1,280,000  条结果 (用时  0.13  秒)  </li></ul></ul><ul><ul><li>...
可是 <ul><li>你知道的 </li></ul><ul><ul><li>浏览器并不是单线程 </li></ul></ul><ul><ul><li>JavaScript 是单线程 ≠ 浏览器是单线程 </li></ul></ul><ul><u...
浏览器线程知多少 <ul><li>UI 渲染线程 /JavaScript 执行线程 </li></ul><ul><li>资源下载线程 (JavaScript, CSS, Image, Object) </li></ul><ul><li>Ajax...
前端,你伤不起 <ul><li>在所有下载线程中 </li></ul><ul><ul><li>为什么 CSS 文件加载不会 block 页面? </li></ul></ul><ul><ul><li>为什么图片加载不会 block 页面? </l...
关于 AJAX 的同步异步 <ul><li>同步与异步的差别来自于 AJAX 的盛行 </li></ul><ul><li>同步 Ajax 会锁住整个浏览器,直到请求完成 </li></ul><ul><li>而异步请求则无影响,但是接收结果必须通...
被各种 ajax 库宠坏的孩子们 <ul><li>看看最原始的 Ajax 吧 </li></ul><ul><ul><li>var httpRequest; if (window.XMLHttpRequest) { // Mozilla, Saf...
异步 Ajax 模型 05/09/11
同步 Ajax 模型 05/09/11
消息模型与事件驱动 <ul><li>在所有的浏览器线程之间的交互,是通过消息来传递的 </li></ul><ul><li>我们唯一能控制的线程是 UI 线程 </li></ul><ul><li>其余的线程我们只能通过侦听事件消息才能得到数据 <...
消息编程模型  Vs.  多线程编程 <ul><li>消息模型是构建在多线程的基础之上的 </li></ul><ul><li>在 JavaScript 的领域里 ( 包括 NodeJS),  多线程的细节被隔离 </li></ul><ul><l...
从 Web Worker 看浏览器的线程 <ul><li>将 JavaScript 执行线程脱离 UI 线程 </li></ul><ul><li>Web Worker 的线程也可以控制,但是交互依然是消息 </li></ul>05/09/11
浏览器是最成熟的消息模型应用 <ul><li>异步 Ajax </li></ul><ul><li>各种资源的下载消息通知 </li></ul><ul><li>浏览器原生事件驱动 </li></ul><ul><ul><li>UI 事件驱动 </l...
消息模型的优势 <ul><li>编程模型简化 </li></ul><ul><ul><li>多线程框架由底层实现和托管,我们只负责调用 API 启动线程,发送消息和侦听消息 </li></ul></ul><ul><ul><li>对编程人员隔离多线...
消息模型的弱势 <ul><li>无法手动构造多线程实现并行和异步 </li></ul><ul><ul><li>严重依赖应用的支持 </li></ul></ul><ul><ul><ul><li>以 web worker 和 websocket 为...
NodeJS 是一个跑在 Server 端的浏览器 浏览器架构 (Chrome) NodeJS 架构 05/09/11
未来世界也许会是这样的 <ul><li>它也许是浏览器 </li></ul><ul><li>它也许是 NodeJS </li></ul><ul><li>它也许什么应用都不是,但是应用都跑在这上面 </li></ul>05/09/11
为何 JScript 在服务端会死掉? <ul><li>var objConn = Server.CreateObject(&quot;ADODB.Connection&quot;); </li></ul><ul><li>// open our...
JScript Vs. NodeJS <ul><li>JScript 之死 </li></ul><ul><ul><li>摒弃了 JavaScript 在浏览器中的异步机制 </li></ul></ul><ul><ul><li>完全无视消息模型 ...
结语 <ul><li>Block UI 的 JavaScript 不是好 JavaScript </li></ul><ul><li>无消息模型,不 JavaScript </li></ul><ul><li>无事件驱动,不 JavaScript ...
References <ul><li>http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/ </li></ul><ul><li>http://...
05/09/11 Thanks
Upcoming SlideShare
Loading in...5
×

从无阻塞并行脚本加载(Lab.js)到浏览器消息模型

3,592

Published on

web标准化交流会第十八期上海站分享。
Jackson Tian:从无阻塞脚本加载(LAB.js)到浏览器线程模型

Published in: Technology, Education
2 Comments
17 Likes
Statistics
Notes
  • dynamic load js with no blocking
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
3,592
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
116
Comments
2
Likes
17
Embeds 0
No embeds

No notes for slide

Transcript of "从无阻塞并行脚本加载(Lab.js)到浏览器消息模型"

  1. 1. 从无阻塞脚本加载 (LAB.js) 到浏览器线程模型 Jackson Tian/ 田永强 @ 朴灵 at SAP 05/09/11
  2. 2. Agenda <ul><li>为什么 script 会阻塞页面解析 </li></ul><ul><li>如何实现无阻塞脚本加载 </li></ul><ul><li>依赖管理与无阻塞并行加载与顺序执行 (LAB.js 实现机制 ) </li></ul><ul><li>无阻塞脚本加载潜在问题 </li></ul><ul><li>为什么要谈谈 JavaScript 线程 </li></ul><ul><li>为什么要谈谈同步与异步 </li></ul><ul><li>浏览器线程消息模型 </li></ul><ul><li>从 Web Worker 看浏览器的线程 </li></ul><ul><li>NodeJS 的单线程与多线程 </li></ul>05/09/11
  3. 3. 说到无阻塞脚本加载 <ul><li>你不得不知道的大牛是 </li></ul><ul><li>Steve Souders </li></ul><ul><li>At  Google  on web performance and open source initiatives. </li></ul><ul><li>http://www.stevesouders.com/ </li></ul>05/09/11
  4. 4. 为什么 script 标签会阻塞页面解析 05/09/11
  5. 5. 05/09/11
  6. 6. Document.write 是魔鬼 <ul><li>队列的基本原则 </li></ul><ul><ul><li>先进先出原则( FIFO, First-In-First-Out ) http://zh.wikipedia.org/wiki/%E9%98%9F%E5%88%97 </li></ul></ul><ul><li>Document.write 破坏了原始的 UI 更新队列 </li></ul><ul><li>从 document.write 来看, JavaScript 设计之初只是用来做 Web 页面辅助的 </li></ul>05/09/11
  7. 7. 05/09/11
  8. 8. Alert 也是魔鬼 <ul><li>alert(“I am evil, too.”); </li></ul><ul><li>是否有人通过 alert 来 debug JavaScript 程序呢? </li></ul><ul><ul><li>for(var i=0; i< 1000; i++) { alert(“Hi, ” + i); } </li></ul></ul><ul><li>alert 最坏的地方在于它中断整个 UI 线程 </li></ul><ul><li>用户体验的敌人 ( 桌面浏览器 ) </li></ul><ul><li>confirm , prompt 方法也是类似的 </li></ul>05/09/11
  9. 9. 为什么 script 标签会阻塞页面解析 <ul><li>基于以上的历史原因, JavaScript 线程与 UI 共用同一进程,而且 JS 任务优先于 UI 任务 </li></ul><ul><li>浏览器会在遇到 Script 标签的时候进行解析和执行 </li></ul><ul><li>如果 Script 是外链的话,还要等待下载 </li></ul><ul><li>如果页面存在多个外链脚本,下载是串行的 </li></ul><ul><li>在 IE8, Firefox3.5, Safari4 和 Chrome2 开始允许并行下载 JavaScript 文件,但是依然会阻塞页面的其他资源的下载 </li></ul>05/09/11
  10. 10. Chromium 解析流程 05/09/11 此图由 Tapir( 貘 ) 提供,感谢他
  11. 11. YSlow 的 35 条军规 <ul><ul><li>Put Scripts at the Bottom </li></ul></ul><ul><ul><ul><li>http://developer.yahoo.com/performance/rules.html#js_bottom </li></ul></ul></ul><ul><ul><ul><li>如果脚本的下载 + 解析 + 执行的时间太久, UI 队列没有得到执行,页面会出现空白 </li></ul></ul></ul><ul><ul><ul><li>Yahoo !建议将所有的脚本都放在 </body> 之前,让 UI 队列优先执行和显示。 </li></ul></ul></ul><ul><ul><li>Minimize HTTP Requests </li></ul></ul><ul><ul><ul><li>http://developer.yahoo.com/performance/rules.html#num_http </li></ul></ul></ul><ul><ul><ul><li>页面脚本过多的情况下,通过 combo 和 compress 减少请求数 </li></ul></ul></ul><ul><ul><li>问题? </li></ul></ul><ul><ul><ul><li>在 </body> 之前存在一个较大的脚本文件需要下载和执行 </li></ul></ul></ul><ul><ul><ul><li>UI 在 ready 之后,需要较长时间等待脚本的下载和执行,在脚本 ready 之前, UI 是出于无事件响应状态的。 </li></ul></ul></ul>05/09/11
  12. 12. 无阻塞脚本加载 05/09/11
  13. 13. Defer 属性 <ul><li>HTML4 标准为 <script> 标签定义了 defer 属性,以此声明告诉浏览器内容中不包含 document.write 之类破坏 DOM 的脚本 </li></ul><ul><li>浏览器会延迟(无阻塞)下载脚本,并按 <script> 脚本顺序执行。 </li></ul><ul><li>在 onload 事件前执行 </li></ul><ul><li>实现 / 支持情况 </li></ul><ul><ul><li>IE4.0 </li></ul></ul><ul><ul><li>Firefox3.5 </li></ul></ul>05/09/11
  14. 14. Async 属性 <ul><li>HTML5 标准为 <script> 标签定义了 async 属性 </li></ul><ul><li>与 defer 属性相同的是脚本会无阻塞加载 </li></ul><ul><li>与 defer 属性不同的是脚本在加载完了立即执行,并非按照 <script> 标签顺序执行 </li></ul><ul><li>实现 / 支持情况 </li></ul><ul><ul><li>Firefox3.6 </li></ul></ul><ul><ul><li>Opera10.5 </li></ul></ul><ul><ul><li>Safari </li></ul></ul><ul><ul><li>Chrome </li></ul></ul><ul><ul><li>IE9.0 ( defer 的别名?) </li></ul></ul>05/09/11
  15. 15. 标准与实现之间的差距 <ul><li>动态脚本元素 </li></ul><ul><ul><li>利用一小段脚本去创建 <script> 标签,实现无阻塞加载 </li></ul></ul><ul><ul><li>var script = document.createElement('script'); script.src = 'myscript.js'; var head = document.getElementsByTagName('head')[0]; head.appendChild(script); </li></ul></ul>05/09/11
  16. 16. Script 标签的 onload 事件 <ul><li>  function loadScript(url, callback){ </li></ul><ul><li>    var script = document.createElement(”script”)     script.type = “text/javascript”; </li></ul><ul><li>    if (script. readyState ){  //IE         script. onreadystatechange = function(){             if (script. readyState == “loaded” ||                     script. readyState == “complete”){                 script.onreadystatechange = null;                 callback();             }         };     } else {  //Others         script. onload = function(){             callback();         };     } </li></ul><ul><li>    script.src = url;     document.body.appendChild(script); } </li></ul>05/09/11
  17. 17. 无阻塞脚本加载实例 <ul><li>Google Analytics 代码 </li></ul><ul><ul><li>http://code.google.com/intl/zh-CN/apis/analytics/docs/tracking/asyncTracking.html </li></ul></ul>05/09/11
  18. 18. XMLHttprequest 脚本注入 <ul><li>$.get(“script.js”, function (responseText) { var script = document.createElement(“script”); script.type=“text/javascript”; script.text = “responseText”; document.body.appendChild(script); }); </li></ul><ul><li>可以控制下载和执行 </li></ul><ul><li>该方法基于 Ajax ,受同源策略影响,无法使用 CDN 。 </li></ul>05/09/11
  19. 19. XMLHttpRequest Eval <ul><li>$.get(“script.js”, function (responseText) { eval(responseText); }); </li></ul><ul><li>与 XMLHttpRequest 具有相同的优点和缺点 </li></ul><ul><li>但是, Eval is Evil 。 </li></ul>05/09/11
  20. 20. document.write Script Tag <ul><li>  document.write(“<script src=‘script.js’> </script>”); </li></ul><ul><li>只有 IE 生效 </li></ul><ul><li>如果在文档流关闭之后再调用 document.write() ,整个 DOM 会被毁坏 </li></ul>05/09/11
  21. 21. Script in Iframe <ul><li>我也不知道怎么搞。 </li></ul><ul><li>很复杂。 </li></ul><ul><li>Google 都 Google 不到。 </li></ul><ul><li>也许是 <iframe src=“#”></iframe> </li></ul>05/09/11
  22. 22. 问题总结 <ul><li>同源策略限制 (XHR inject, XHR eval,Iframe) </li></ul><ul><li>顺序执行 ( 动态 script 元素 , async) </li></ul><ul><li>浏览器支持 (async, defer) </li></ul><ul><li>并行下载与顺序执行 </li></ul>05/09/11
  23. 23. 各种方法支持一览 05/09/11 方法 并行加载 顺序执行 不受同源限制 浏览器都支持 Defer √ √ √ x Async √ x √ x 动态脚本元素 √ x √ √ XHR Inject √ √ x √ XHR Eval √ √ x √ Document.write √ √ √ x Iframe √ ? x √
  24. 24. 无顺序执行的要求情况下 05/09/11 方法 并行加载 顺序执行 不受同源限制 浏览器都支持 Defer √ √ √ x Async √ x √ x 动态脚本元素 √ x √ √ XHR Inject √ √ x √ XHR Eval √ √ x √ Document.write √ √ √ x Iframe √ ? x √
  25. 25. 05/09/11
  26. 26. 如何控制依赖加载 <ul><li>通过 onload 事件控制? loadScript(“file1.js”, function() { loadScript(“file2.js”, function() { loadScript(“file3.js”, function() { alert(“All ready.”); }); }); }); </li></ul><ul><li>这是串行加载的 </li></ul>05/09/11
  27. 27. 如何控制依赖加载 <ul><li>或者采用 defer ? <script src=“script1.js” defer></script> <script src=“script2.js” defer></script> <script src=“script3.js” defer></script> </li></ul><ul><li>显然浏览器支持不够 </li></ul>05/09/11
  28. 28. 如何控制依赖加载 <ul><li>更或者通过 XHR 动态加载,顺序执行 </li></ul><ul><li>同源策略怎么办? </li></ul>05/09/11
  29. 29. 如何控制依赖加载 <ul><li>在 Server 端组织好脚本顺序,并且 combo 成一个文件 </li></ul><ul><li>这是一个好主意!!! </li></ul><ul><li>但是总有你不能 combo 的文件,比如本地化的资源文件 </li></ul>05/09/11
  30. 30. <ul><li>依赖加载 ≠ 必须顺序加载 ≠ 串行加载 </li></ul>05/09/11
  31. 31. <ul><li>顺序执行 ≠ 立即执行 </li></ul>05/09/11
  32. 32. 有没有一种方法 <ul><li>能实现并行下载 </li></ul><ul><li>能实现顺序执行 </li></ul><ul><li>能没有副作用 </li></ul>05/09/11
  33. 33. LAB.js <ul><li>@getify </li></ul><ul><li>Kyle Simpson </li></ul><ul><li>公司: Getify Solutions </li></ul><ul><li>LABjs 被很多大网站所采用,包括新版的 Twitter ,  Zappos , 以及 Vimeo . </li></ul><ul><li>Kyle Simpson 在 Steve Sounders 的启示下写下了 LABjs 这个库,用于管理并行加载和顺序执行 </li></ul>05/09/11
  34. 34. LABjs 的诀窍 <ul><li>对于 Firefox/Opera ,采用动态 Script DOM element 可以完美地实现并行下载和顺序执行 </li></ul><ul><li>对于 Safari/Chrome ,无法保证顺序执行,但是 LABjs 通过插入一个 <script type=“text/cache” src=“#”> 来实现。 IE/Safari/Chrome 浏览器会下载文件到缓存并触发 onload 事件,但不会执行 </li></ul>05/09/11
  35. 35. <ul><li>在需要的文件下载完成之后,再次通过插入正确的 type=“text/javascript” 而且监听 onload 来完成对于顺序执行的控制 </li></ul><ul><li>LABjs 判断 script 文件是否同域文件,优先选择 XHR Injection 实现并行下载,顺序执行 </li></ul><ul><li>Text/cache 严重依赖浏览器的非标准特性 </li></ul>LABjs 的诀窍 05/09/11
  36. 36. LABjs 示例 <ul><li>Sample Code </li></ul><ul><ul><li><script src=&quot;LAB.js&quot;></script> <script> $LAB .script(&quot;http://remote/jquery.js”).wait() .script(&quot;/local/plugin1.jquery.js&quot;) .script(&quot;/local/plugin2.jquery.js&quot;).wait() .script(&quot;/local/init.js&quot;).wait(function(){ initMyPage(); }); </script> </li></ul></ul>05/09/11
  37. 37. LABjs 方法 <ul><li>主要方法 </li></ul><ul><ul><li>Script() </li></ul></ul><ul><ul><ul><li>可以多次调用 script 方法来并行加载脚本 </li></ul></ul></ul><ul><ul><li>Wait() </li></ul></ul><ul><ul><ul><li>通过调用 wait 方法来保证序列中的脚本执行顺序 </li></ul></ul></ul>05/09/11
  38. 38. LABjs API 示意 05/09/11
  39. 39. 题外话 <ul><li>曾经 Firefox4 试图改掉动态脚本元素按顺序执行的特性,使得像 Chrome/Safari 一样 </li></ul><ul><li>那么,在面对 CDN 脚本, text/cache 失效的情况下, LABjs 会无可奈何地进行串行下载 </li></ul><ul><li>有链接为证: </li></ul><ul><ul><li>http://blog.getify.com/2010/10/ff4-script-loaders-and-order-preservation/ </li></ul></ul><ul><ul><li>http://blog.getify.com/2010/10/mozilla-labjs-the-story-unfolds/ </li></ul></ul><ul><ul><li>http://blog.getify.com/2010/10/mozilla-labjs-part-2/ </li></ul></ul>05/09/11
  40. 40. 题外话 <ul><li>后来, getify 赢了 </li></ul>05/09/11
  41. 41. 无阻塞脚本与 DOM <ul><li>在脚本加载完成的时候, DOM 可能 </li></ul><ul><ul><li>DOM 还没有 DOMContentLoaded( 加载速度快或者来自 cache) </li></ul></ul><ul><ul><ul><li>访问 DOM 是危险的 </li></ul></ul></ul><ul><ul><li>DOM 可能已经 DOMContentLoaded 了 </li></ul></ul><ul><ul><ul><li>绑定 DOMContentLoaded 事件永远也不会被触发 </li></ul></ul></ul><ul><ul><ul><li>如何判断 DOM 是否 ready </li></ul></ul></ul><ul><ul><li>DOM 甚至已经 Onload 了 (IE) </li></ul></ul>05/09/11
  42. 42. 如何解决以上问题? <ul><li>DOM 还没有 DOMContentLoaded( 加载速度快或者来自 cache) </li></ul><ul><ul><li>保证 DOM 操作注册在 DOMContentLoaded 事件中 </li></ul></ul><ul><li>DOM 可能已经 DOMContentLoaded 了 </li></ul><ul><ul><li>绑定 DOMContentLoaded 事件永远也不会被触发 </li></ul></ul><ul><ul><li>通过 document.readyState == “complete” 判断 DOMready </li></ul></ul><ul><li>DOM 甚至已经 Onload 了 (IE) </li></ul><ul><ul><li>document.readyState 依然有效 </li></ul></ul>05/09/11
  43. 43. 回顾 <ul><li>Combo 脚本文件,以减少链接数 </li></ul><ul><li>优先加载和无阻塞加载,实现界面快速响应 </li></ul><ul><li>采用 LABjs 做依赖管理,实现并行下载和顺序执行 </li></ul><ul><li>控制好访问 DOM 的代码,确保在 DOMContentLoaded 后执行 </li></ul>05/09/11
  44. 44. 为什么要啰嗦浏览器线程 <ul><li>无阻塞加载讲得又不深入,还要啰嗦浏览器线程 </li></ul><ul><li>因为扯谈了这么多,目的只是将脚本的下载线程脱离 UI 线程而已 </li></ul><ul><li>设计 JavaScript 执行和 UI 渲染共用 UI 线程的人上辈子是折翼的天使,伤不起 </li></ul>05/09/11
  45. 45. <ul><li>为什么 JavaScript 作为一门编程语言,却没有多线程? </li></ul><ul><li>抱怨 JavaScript 没有多线程的程序员不是好程序员 </li></ul><ul><li>有多少人用 setTimeout 模拟过多线程 </li></ul>JavaScript 线程怨念知多少 05/09/11
  46. 46. JavaScript 线程 <ul><li>JavaScript 的多线程 </li></ul><ul><ul><li>找到约 1,280,000 条结果 (用时 0.13 秒)  </li></ul></ul><ul><ul><li>http://www.google.com.hk/search?sourceid=chrome&ie=UTF-8&q=JavaScript+%E5%A4%9A%E7%BA%BF%E7%A8%8B </li></ul></ul>05/09/11
  47. 47. 可是 <ul><li>你知道的 </li></ul><ul><ul><li>浏览器并不是单线程 </li></ul></ul><ul><ul><li>JavaScript 是单线程 ≠ 浏览器是单线程 </li></ul></ul><ul><ul><li>WebApp ≠ JavaScript App </li></ul></ul><ul><ul><li>WebApp = 浏览器 + JavaScript + CSS + HTML + Images + …. + API </li></ul></ul><ul><li>所以 </li></ul><ul><ul><li>JavaScript 的单线程是有原因的 </li></ul></ul>05/09/11
  48. 48. 浏览器线程知多少 <ul><li>UI 渲染线程 /JavaScript 执行线程 </li></ul><ul><li>资源下载线程 (JavaScript, CSS, Image, Object) </li></ul><ul><li>Ajax 线程 </li></ul><ul><li>Web Worker 线程 </li></ul><ul><li>还有?欢迎补充 </li></ul>05/09/11
  49. 49. 前端,你伤不起 <ul><li>在所有下载线程中 </li></ul><ul><ul><li>为什么 CSS 文件加载不会 block 页面? </li></ul></ul><ul><ul><li>为什么图片加载不会 block 页面? </li></ul></ul><ul><ul><li>为什么 flash 加载不会 block 页面? </li></ul></ul><ul><ul><li>为什么 ajax 还有同步和异步之分? </li></ul></ul><ul><ul><li>为什么 JavaScript 文件会 block UI ? </li></ul></ul>05/09/11
  50. 50. 关于 AJAX 的同步异步 <ul><li>同步与异步的差别来自于 AJAX 的盛行 </li></ul><ul><li>同步 Ajax 会锁住整个浏览器,直到请求完成 </li></ul><ul><li>而异步请求则无影响,但是接收结果必须通过回调函数 </li></ul>05/09/11
  51. 51. 被各种 ajax 库宠坏的孩子们 <ul><li>看看最原始的 Ajax 吧 </li></ul><ul><ul><li>var httpRequest; if (window.XMLHttpRequest) { // Mozilla, Safari, ... httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE httpRequest = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;); } httpRequest.onreadystatechange = function(){ if (httpRequest.readyState === 4) { </li></ul></ul><ul><ul><li>if (httpRequest.status === 200) { // perfect! } else { // there was a problem with the request, // for example the response may be a 404 (Not Found) // or 500 (Internal Server Error) response codes } </li></ul></ul><ul><ul><li> } else { </li></ul></ul><ul><ul><li>     // still not ready </li></ul></ul><ul><ul><li> } }; httpRequest.open('GET', ‘http://url', true); httpRequest.send(null); </li></ul></ul>05/09/11
  52. 52. 异步 Ajax 模型 05/09/11
  53. 53. 同步 Ajax 模型 05/09/11
  54. 54. 消息模型与事件驱动 <ul><li>在所有的浏览器线程之间的交互,是通过消息来传递的 </li></ul><ul><li>我们唯一能控制的线程是 UI 线程 </li></ul><ul><li>其余的线程我们只能通过侦听事件消息才能得到数据 </li></ul><ul><li>所有的事件 handler 都由浏览器来做事件驱动 </li></ul>05/09/11
  55. 55. 消息编程模型 Vs. 多线程编程 <ul><li>消息模型是构建在多线程的基础之上的 </li></ul><ul><li>在 JavaScript 的领域里 ( 包括 NodeJS), 多线程的细节被隔离 </li></ul><ul><li>应用里的多线程操作通过事件驱动和消息传递暴露给程序员 </li></ul><ul><li>鼓吹消息模型而鄙视多线程模型的程序员不是好的工程师 </li></ul>05/09/11
  56. 56. 从 Web Worker 看浏览器的线程 <ul><li>将 JavaScript 执行线程脱离 UI 线程 </li></ul><ul><li>Web Worker 的线程也可以控制,但是交互依然是消息 </li></ul>05/09/11
  57. 57. 浏览器是最成熟的消息模型应用 <ul><li>异步 Ajax </li></ul><ul><li>各种资源的下载消息通知 </li></ul><ul><li>浏览器原生事件驱动 </li></ul><ul><ul><li>UI 事件驱动 </li></ul></ul><ul><ul><li>网络事件驱动 </li></ul></ul>05/09/11
  58. 58. 消息模型的优势 <ul><li>编程模型简化 </li></ul><ul><ul><li>多线程框架由底层实现和托管,我们只负责调用 API 启动线程,发送消息和侦听消息 </li></ul></ul><ul><ul><li>对编程人员隔离多线程的烦恼 </li></ul></ul><ul><li>程序耦合性低 </li></ul><ul><ul><li>程序代码属于被 trigger 的状况,不耦合于目标代码 </li></ul></ul><ul><ul><li>我讨厌异步特有的 callback 编程,但是我喜欢消息模型 </li></ul></ul><ul><li>原生的 AOP 编程 </li></ul>05/09/11
  59. 59. 消息模型的弱势 <ul><li>无法手动构造多线程实现并行和异步 </li></ul><ul><ul><li>严重依赖应用的支持 </li></ul></ul><ul><ul><ul><li>以 web worker 和 websocket 为例,只有浏览器支持的情况下,才能享受到消息模型的好处 </li></ul></ul></ul><ul><li>事件驱动依赖应用实现 </li></ul><ul><ul><li>可以手动触发自定义事件,但是对于特殊事件无法触发 </li></ul></ul>05/09/11
  60. 60. NodeJS 是一个跑在 Server 端的浏览器 浏览器架构 (Chrome) NodeJS 架构 05/09/11
  61. 61. 未来世界也许会是这样的 <ul><li>它也许是浏览器 </li></ul><ul><li>它也许是 NodeJS </li></ul><ul><li>它也许什么应用都不是,但是应用都跑在这上面 </li></ul>05/09/11
  62. 62. 为何 JScript 在服务端会死掉? <ul><li>var objConn = Server.CreateObject(&quot;ADODB.Connection&quot;); </li></ul><ul><li>// open our ADO connection and Execute the SQL command </li></ul><ul><li>objConn.Open(&quot;dsn=helpdesk&quot;, &quot;sa&quot;, &quot;&quot;); </li></ul><ul><li>objConn.Execute(strCommandText); </li></ul><ul><li>var returnErrCode = </li></ul><ul><li>objConn.Execute(&quot;SELECT @@ERROR as errorCode&quot;).GetString(); </li></ul><ul><li>objConn.Close(); </li></ul><ul><li>objConn = null; </li></ul>05/09/11
  63. 63. JScript Vs. NodeJS <ul><li>JScript 之死 </li></ul><ul><ul><li>摒弃了 JavaScript 在浏览器中的异步机制 </li></ul></ul><ul><ul><li>完全无视消息模型 </li></ul></ul><ul><ul><li>无多线程支持 </li></ul></ul><ul><ul><li>在 Server 端,表现与 PHP 和 ASP 无异 </li></ul></ul><ul><li>NodeJS 之生 </li></ul><ul><ul><li>延续 JavaScript 在浏览器端赖以生存的特性 </li></ul></ul><ul><ul><li>异步,消息模型,事件驱动 </li></ul></ul><ul><ul><li>向程序员屏蔽多线程 </li></ul></ul>05/09/11
  64. 64. 结语 <ul><li>Block UI 的 JavaScript 不是好 JavaScript </li></ul><ul><li>无消息模型,不 JavaScript </li></ul><ul><li>无事件驱动,不 JavaScript </li></ul><ul><li>浏览器是多线程的, JavaScript 是单线程 </li></ul><ul><li>上一条适用于 NodeJS </li></ul>05/09/11
  65. 65. References <ul><li>http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/ </li></ul><ul><li>http://www.blog.highub.com/mobile-2/mobile-safari-scripts-loading-without-blocking/ </li></ul><ul><li>http://blogs.sitepoint.com/non-blocking-async-defer/ </li></ul>05/09/11
  66. 66. 05/09/11 Thanks
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×