Your SlideShare is downloading. ×
0
 
the importance of frontend performance 17% 83% iGoogle, primed cache 9% 91% iGoogle, empty cache
14 RULES <ul><li>MAKE FEWER HTTP REQUESTS </li></ul><ul><li>USE A CDN </li></ul><ul><li>ADD AN EXPIRES HEADER </li></ul><u...
web performance guy
Even Faster Web Sites Splitting the initial payload Loading scripts without blocking Coupling asynchronous scripts Positio...
Why focus on JavaScript? AOL eBay Facebook MySpace Wikipedia Yahoo! YouTube
scripts block <script src=&quot;A.js&quot;>  blocks parallel downloads and rendering 7 secs: IE 8, FF 3.5, Chr 2, Saf 4 9 ...
MSN.com: parallel scripts Scripts and other resources downloaded in parallel! How? Secret sauce?! var p= g.getElementsByTa...
Loading Scripts Without Blocking XHR Eval XHR Injection Script in Iframe Script DOM Element Script Defer document.write Sc...
XHR Eval script must have same domain as main page must refactor script var xhrObj = getXHRObject(); xhrObj.onreadystatech...
XHR Injection var xhrObj = getXHRObject(); xhrObj.onreadystatechange =  function() {  if ( xhrObj.readyState != 4 ) return...
Script in Iframe <iframe  src='A.html'  width=0 height=0  frameborder=0 id=frame1></iframe>  <ul><li>iframe must have same...
Script DOM Element var se = document.createElement('script'); se.src = 'http://anydomain.com/A.js'; document.getElementsBy...
Script Defer <script  defer  src='A.js'></script> supported in IE and FF 3.1+ script and main page domains can differ no n...
document.write  Script Tag document.write (&quot;<script type='text/javascript' src='A.js'> </script>&quot;); parallelizat...
browser busy indicators
Load Scripts Without Blocking * Only other document.write scripts are downloaded in parallel (in the same script block).
and the winner is... XHR Eval XHR Injection Script in iframe Script DOM Element Script Defer Script DOM Element Script Def...
menu.js image.gif
asynchronous JS example: menu.js <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var domscript = docum...
before after menu.js image.gif menu.js image.gif
Loading Scripts Without Blocking * Only other document.write scripts are downloaded in parallel (in the same script block)...
<ul><li>what about </li></ul><ul><li>inlined code  </li></ul><ul><li>that depends on the script? </li></ul>
coupling techniques <ul><li>hardcoded callback </li></ul><ul><li>window onload </li></ul><ul><li>timer </li></ul><ul><li>d...
technique 1: hardcoded callback <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['cou...
technique 2: window onload <ul><li><iframe src=&quot;menu.php&quot; width=0 height=0 frameborder=0> </iframe> </li></ul><u...
technique 3: timer <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var domscript = document.createElem...
John Resig's degrading script tags <ul><li><script src=&quot;menu-degrading.js&quot; type=&quot;text/javascript&quot;> </l...
technique 4: degrading script tags <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['...
technique 5: script onload <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-n...
<ul><li>what about </li></ul><ul><li>multiple scripts  </li></ul><ul><li>that depend on each other,  </li></ul><ul><li>and...
multiple script example: menutier.js <ul><li><script src=&quot;menu.js&quot; type=&quot;text/javascript&quot;></script> </...
technique 1: managed XHR <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aRaceConditions = [['coup...
EFWS.loadScriptXhrInjection <ul><li>// Load an external script.  </li></ul><ul><li>// Optionally call a callback and prese...
EFWS.injectScripts <ul><li>// Process queued scripts to see if any are ready to inject. </li></ul><ul><li>injectScripts: f...
technique 2: DOM Element and Doc Write Firefox & Opera – use Script DOM Element IE – use  document.write  Script Tag Safar...
EFWS.loadScripts <ul><li>loadScripts: function(aUrls, onload) { </li></ul><ul><li>// first pass: see if any of the scripts...
multiple scripts with dependencies <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aRaceConditions...
asynchronous scripts wrap-up
case study: Google Analytics <ul><li>recommended pattern: 1 </li></ul><ul><li><script type=&quot;text/javascript&quot;> </...
case study: dojox.analytics.Urchin 1 <ul><li>_loadGA: function(){ </li></ul><ul><li>var gaHost = (&quot;https:&quot; == do...
asynchronous loading & coupling <ul><li>async technique: Script DOM Element </li></ul><ul><ul><li>easy, cross-browser </li...
flushing the document early <ul><li>gotchas: </li></ul><ul><ul><li>PHP output_buffering –  ob_flush() </li></ul></ul><ul><...
flushing and domain blocking <ul><li>you might need to move flushed resources to a domain different from the HTML doc </li...
successful flushing <ul><li>Google Search </li></ul><ul><li>external resource downloaded early </li></ul><ul><li>content v...
performance analyzers (HPWS) YSlow Page Speed Pagetest VRTA neXpert combine JS & CSS X X X use CSS sprites X X use a CDN X...
performance analyzers (EFWS) YSlow Page Speed Pagetest VRTA neXpert don't block UI thread split JS payload X load scripts ...
performance analyzers (other) YSlow Page Speed Pagetest VRTA neXpert use persistent conns X X X reduce cookies 2.0 X X X a...
<ul><li>focus on the frontend </li></ul><ul><li>run YSlow ( http://developer.yahoo.com/yslow ) </li></ul><ul><li>and Page ...
<ul><li>Bing: </li></ul><ul><li>Yahoo: </li></ul><ul><li>Google: </li></ul><ul><li>AOL: </li></ul><ul><li>Shopzilla: </li>...
<ul><li>hardware – reduced load </li></ul><ul><ul><li>Shopzilla – 50% fewer servers </li></ul></ul><ul><li>bandwidth – red...
<ul><li>if you want </li></ul><ul><ul><li>better user experience </li></ul></ul><ul><ul><li>more revenue </li></ul></ul><u...
Steve Souders [email_address] http://stevesouders.com/docs/tae-20090914.ppt book signing immediately 3:30-3:50
Upcoming SlideShare
Loading in...5
×

Even Faster Web Sites at The Ajax Experience

2,445

Published on

Even Faster Web Sites covering loading scripts without blocking, coupling asynchronous scripts, and flushing the document early.

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,445
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
37
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide
  • cc: http://www.flickr.com/photos/rollerfan/2868949733/
  • Data source: Steve Souders Tested on IE6 on Comcast cable modem (~5 mbps) medium powered PC, April 2008.
  • photo courtesy of Vicki &amp; Chuck Rogers: http://www.flickr.com/photos/two-wrongs/205467442/
  • Data Source: Steve Souders aol 76% ebay 45% facebook 41% google 42% live search 9% msn 37% myspace 37% yahoo 45% youtube 60% wikipedia 26% average 42%
  • Of the ten top sites, MSN.com (Script DOM Element), Live Search (Script in Iframe), and Yahoo (Script DOM Element) use advanced script loading techniques.
  • All of these allow for parallel downloads, but none of them allow for parallel JS execution – that&apos;s not possible (currently, WebKit is doing some stuff on that).
  • Audio (IE &amp;quot;click&amp;quot;) is another busy indicator. Delayed rendering and delayed onload (&amp;quot;done&amp;quot;) are other busy indicators. Sometimes busy indicators are bad, sometimes good.
  • Data source: Steve Souders
  • I&apos;ll do JavaScript and PHP implementations of this logic soon.
  • Data source: Steve Souders
  • putting code in the script block doesn&apos;t work in any browser; you have to add stuff to the external script this doesn&apos;t load asynchronously
  • Newer browsers (IE8, Saf4, Chr2) work, but mainstream browsers need a workaround.
  • Newer browsers (IE8, Saf4, Chr2) work, but mainstream browsers need a workaround.
  • loadInterval is 420 ms
  • esp. good when your HTML document takes more than 10-20%, and when users have high latency.
  • 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views
  • 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views
  • 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views
  • 72 years = 2,270,592,000 seconds = 500ms * 4.4B page views
  • &amp;quot;thank you&amp;quot; by nj dodge: http://flickr.com/photos/nj_dodge/187190601/
  • Transcript of "Even Faster Web Sites at The Ajax Experience"

    1. 2. the importance of frontend performance 17% 83% iGoogle, primed cache 9% 91% iGoogle, empty cache
    2. 3. 14 RULES <ul><li>MAKE FEWER HTTP REQUESTS </li></ul><ul><li>USE A CDN </li></ul><ul><li>ADD AN EXPIRES HEADER </li></ul><ul><li>GZIP COMPONENTS </li></ul><ul><li>PUT STYLESHEETS AT THE TOP </li></ul><ul><li>PUT SCRIPTS AT THE BOTTOM </li></ul><ul><li>AVOID CSS EXPRESSIONS </li></ul><ul><li>MAKE JS AND CSS EXTERNAL </li></ul><ul><li>REDUCE DNS LOOKUPS </li></ul><ul><li>MINIFY JS </li></ul><ul><li>AVOID REDIRECTS </li></ul><ul><li>REMOVE DUPLICATE SCRIPTS </li></ul><ul><li>CONFIGURE ETAGS </li></ul><ul><li>MAKE AJAX CACHEABLE </li></ul>
    3. 4. web performance guy
    4. 5. Even Faster Web Sites Splitting the initial payload Loading scripts without blocking Coupling asynchronous scripts Positioning inline scripts Sharding dominant domains Flushing the document early Using iframes sparingly Simplifying CSS Selectors Understanding Ajax performance.......... Doug Crockford Creating responsive web apps............ Ben Galbraith, Dion Almaer Writing efficient JavaScript............. Nicholas Zakas Scaling with Comet..................... Dylan Schiemann Going beyond gzipping............... Tony Gentilcore Optimizing images................... Stoyan Stefanov, Nicole Sullivan
    5. 6. Why focus on JavaScript? AOL eBay Facebook MySpace Wikipedia Yahoo! YouTube
    6. 7. scripts block <script src=&quot;A.js&quot;> blocks parallel downloads and rendering 7 secs: IE 8, FF 3.5, Chr 2, Saf 4 9 secs: IE 6-7, FF 3.0, Chr 1, Op 9-10, Saf 3
    7. 8. MSN.com: parallel scripts Scripts and other resources downloaded in parallel! How? Secret sauce?! var p= g.getElementsByTagName(&quot;HEAD&quot;)[0]; var c=g.createElement(&quot;script&quot;); c.type=&quot;text/javascript&quot;; c.onreadystatechange=n; c.onerror=c.onload=k; c.src=e; p.appendChild(c) MSN
    8. 9. Loading Scripts Without Blocking XHR Eval XHR Injection Script in Iframe Script DOM Element Script Defer document.write Script Tag
    9. 10. XHR Eval script must have same domain as main page must refactor script var xhrObj = getXHRObject(); xhrObj.onreadystatechange = function() { if ( xhrObj.readyState != 4 ) return; eval(xhrObj.responseText); }; xhrObj.open('GET', 'A.js', true); xhrObj.send('');
    10. 11. XHR Injection var xhrObj = getXHRObject(); xhrObj.onreadystatechange = function() { if ( xhrObj.readyState != 4 ) return; var se=document.createElement('script'); document.getElementsByTagName('head') [0].appendChild(se); se.text = xhrObj.responseText; }; xhrObj.open('GET', 'A.js', true); xhrObj.send(''); script must have same domain as main page
    11. 12. Script in Iframe <iframe src='A.html' width=0 height=0 frameborder=0 id=frame1></iframe> <ul><li>iframe must have same domain as main page </li></ul><ul><li>must refactor script: </li></ul><ul><ul><li>// access iframe from main page </li></ul></ul><ul><ul><li>window.frames[0].createNewDiv(); </li></ul></ul><ul><ul><li>// access main page from iframe </li></ul></ul><ul><ul><li>parent.document.createElement('div'); </li></ul></ul>
    12. 13. Script DOM Element var se = document.createElement('script'); se.src = 'http://anydomain.com/A.js'; document.getElementsByTagName('head') [0].appendChild(se); script and main page domains can differ no need to refactor JavaScript
    13. 14. Script Defer <script defer src='A.js'></script> supported in IE and FF 3.1+ script and main page domains can differ no need to refactor JavaScript
    14. 15. document.write Script Tag document.write (&quot;<script type='text/javascript' src='A.js'> </script>&quot;); parallelization only works in IE parallel downloads for scripts, nothing else all document.write s must be in same script block
    15. 16. browser busy indicators
    16. 17. Load Scripts Without Blocking * Only other document.write scripts are downloaded in parallel (in the same script block).
    17. 18. and the winner is... XHR Eval XHR Injection Script in iframe Script DOM Element Script Defer Script DOM Element Script Defer Script DOM Element Script DOM Element (FF) Script Defer (IE) XHR Eval XHR Injection Script in iframe Script DOM Element (IE) XHR Injection XHR Eval Script DOM Element (IE) Managed XHR Injection Managed XHR Eval Script DOM Element Managed XHR Injection Managed XHR Eval Script DOM Element (FF) Script Defer (IE) Managed XHR Eval Managed XHR Injection Script DOM Element (FF) Script Defer (IE) Managed XHR Eval Managed XHR Injection different domains same domains no order preserve order no order no busy show busy show busy no busy preserve order
    18. 19. menu.js image.gif
    19. 20. asynchronous JS example: menu.js <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var domscript = document.createElement('script'); </li></ul><ul><li>domscript.src = &quot;menu.js&quot;; </li></ul><ul><li>document.getElementsByTagName('head')[0].appendChild(domscript); </li></ul><ul><li>var aExamples = </li></ul><ul><li>[ </li></ul><ul><li>['couple-normal.php', 'Normal Script Src'], </li></ul><ul><li>['couple-xhr-eval.php', 'XHR Eval'], </li></ul><ul><li>... </li></ul><ul><li>['managed-xhr.php', 'Managed XHR'] </li></ul><ul><li>]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>init(); </li></ul><ul><li></script> </li></ul>script DOM element approach
    20. 21. before after menu.js image.gif menu.js image.gif
    21. 22. Loading Scripts Without Blocking * Only other document.write scripts are downloaded in parallel (in the same script block). !IE
    22. 23. <ul><li>what about </li></ul><ul><li>inlined code </li></ul><ul><li>that depends on the script? </li></ul>
    23. 24. coupling techniques <ul><li>hardcoded callback </li></ul><ul><li>window onload </li></ul><ul><li>timer </li></ul><ul><li>degrading script tags </li></ul><ul><li>script onload </li></ul>
    24. 25. technique 1: hardcoded callback <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>var domscript = document.createElement('script'); </li></ul><ul><li>domscript.src = &quot;menu.js&quot;; </li></ul><ul><li>document.getElementsByTagName('head')[0].appendChild(domscript); </li></ul><ul><li></script> </li></ul><ul><li>init() is called from within menu.js </li></ul><ul><li>not very flexible </li></ul><ul><li>doesn't work for 3 rd party scripts </li></ul>
    25. 26. technique 2: window onload <ul><li><iframe src=&quot;menu.php&quot; width=0 height=0 frameborder=0> </iframe> </li></ul><ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>if ( window.addEventListener ) { </li></ul><ul><li>window.addEventListener(&quot;load&quot;, init, false); </li></ul><ul><li>} </li></ul><ul><li>else if ( window.attachEvent ) { </li></ul><ul><li>window.attachEvent(&quot;onload&quot;, init); </li></ul><ul><li>} </li></ul><ul><li></script> </li></ul><ul><li>init() is called at window onload </li></ul><ul><li>must use async technique that blocks onload: </li></ul><ul><ul><li>Script in Iframe does this across most browsers </li></ul></ul><ul><li>init() called later than necessary </li></ul>
    26. 27. technique 3: timer <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var domscript = document.createElement('script'); </li></ul><ul><li>domscript.src = &quot;menu.js&quot;; </li></ul><ul><li>document.getElementsByTagName('head')[0].appendChild(domscript); </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>function initTimer(interval) { </li></ul><ul><li>if ( &quot;undefined&quot; === typeof(EFWS) ) { </li></ul><ul><li>setTimeout(initTimer, interval); </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>init(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>initTimer(300); </li></ul><ul><li></script> </li></ul><ul><li>load if interval too low, delay if too high </li></ul><ul><li>slight increased maintenance – EFWS </li></ul>
    27. 28. John Resig's degrading script tags <ul><li><script src=&quot;menu-degrading.js&quot; type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>init(); </li></ul><ul><li></script> </li></ul>at the end of menu-degrading.js: var scripts = document.getElementsByTagName(&quot;script&quot;); var cntr = scripts.length; while ( cntr ) { var curScript = scripts[cntr-1]; if (curScript.src.indexOf(&quot;menu-degrading.js&quot;) != -1) { eval( curScript.innerHTML ); break; } cntr--; } http://ejohn.org/blog/degrading-script-tags/ cleaner clearer safer – inlined code not called if script fails no browser supports it
    28. 29. technique 4: degrading script tags <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'],...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>var domscript = document.createElement('script'); </li></ul><ul><li>domscript.src = &quot;menu-degrading.js&quot;; </li></ul><ul><li>if ( -1 != navigator.userAgent.indexOf(&quot;Opera&quot;) ) { </li></ul><ul><li>domscript.innerHTML = &quot;init();&quot;; </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>domscript.text = &quot;init();&quot;; </li></ul><ul><li>} </li></ul><ul><li>document.getElementsByTagName('head')[0].appendChild(domscript); </li></ul><ul><li></script> </li></ul><ul><li>elegant, flexible (cool!) </li></ul><ul><li>not well known </li></ul><ul><li>doesn't work for 3 rd party scripts (unless...) </li></ul>
    29. 30. technique 5: script onload <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aExamples = [['couple-normal.php', 'Normal Script Src'], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createMenu('examplesbtn', aExamples); </li></ul><ul><li>} </li></ul><ul><li>var domscript = document.createElement('script'); </li></ul><ul><li>domscript.src = &quot;menu.js&quot;; </li></ul><ul><li>domscript.onloadDone = false; </li></ul><ul><li>domscript.onload = function() { </li></ul><ul><li>if ( ! domscript.onloadDone ) { init(); } </li></ul><ul><li>domscript.onloadDone = true; </li></ul><ul><li>}; </li></ul><ul><li>domscript.onreadystatechange = function() { </li></ul><ul><li>if ( &quot;loaded&quot; === domscript.readyState ) { </li></ul><ul><li>if ( ! domscript.onloadDone ) { init(); } </li></ul><ul><li>domscript.onloadDone = true; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>document.getElementsByTagName('head')[0].appendChild(domscript); </li></ul><ul><li></script> </li></ul><ul><li>pretty nice, medium complexity </li></ul>menu.js image.gif
    30. 31. <ul><li>what about </li></ul><ul><li>multiple scripts </li></ul><ul><li>that depend on each other, </li></ul><ul><li>and inlined code </li></ul><ul><li>that depends on the scripts? </li></ul><ul><li>two solutions: </li></ul><ul><ul><li>Managed XHR </li></ul></ul><ul><ul><li>DOM Element and Doc Write </li></ul></ul>
    31. 32. multiple script example: menutier.js <ul><li><script src=&quot;menu.js&quot; type=&quot;text/javascript&quot;></script> </li></ul><ul><li><script src=&quot;menutier.js&quot; type=&quot;text/javascript&quot;></script> </li></ul><ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aRaceConditions = [['couple-normal.php', 'Normal...]; </li></ul><ul><li>var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; </li></ul><ul><li>var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; </li></ul><ul><li>var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; </li></ul><ul><li>var aSubmenus = </li></ul><ul><li>[[&quot;Race Conditions&quot;, aRaceConditions], </li></ul><ul><li>[&quot;Workarounds&quot;, aWorkarounds], </li></ul><ul><li>[&quot;Multiple Scripts&quot;, aMultipleScripts], </li></ul><ul><li>[&quot;General Solution&quot;, aLoadScripts]]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); </li></ul><ul><li>} </li></ul><ul><li></script> </li></ul>
    32. 33. technique 1: managed XHR <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aRaceConditions = [['couple-normal.php', 'Normal...]; </li></ul><ul><li>var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; </li></ul><ul><li>var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; </li></ul><ul><li>var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; </li></ul><ul><li>var aSubmenus = [[&quot;Race Conditions&quot;, aRaceConditions], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); </li></ul><ul><li>} </li></ul><ul><li>EFWS.Script.loadScriptXhrInjection(&quot;menu.js&quot;, null, true); </li></ul><ul><li>EFWS.Script.loadScriptXhrInjection(&quot;menutier.js&quot;, init, true); </li></ul><ul><li></script> </li></ul><ul><li>XHR Injection asynchronous technique does not preserve order – we have to add that </li></ul>before after
    33. 34. EFWS.loadScriptXhrInjection <ul><li>// Load an external script. </li></ul><ul><li>// Optionally call a callback and preserve order. </li></ul><ul><li>loadScriptXhrInjection: function(url, onload, bOrder) { </li></ul><ul><li>var iQ = EFWS.Script.queuedScripts.length; </li></ul><ul><li>if ( bOrder ) { </li></ul><ul><li>var qScript = { response: null, onload: onload, done: false }; </li></ul><ul><li>EFWS.Script.queuedScripts[iQ] = qScript; </li></ul><ul><li>} </li></ul><ul><li>var xhrObj = EFWS.Script.getXHRObject(); </li></ul><ul><li>xhrObj.onreadystatechange = function() { </li></ul><ul><li>if ( xhrObj.readyState == 4 ) { </li></ul><ul><li>if ( bOrder ) { </li></ul><ul><li>EFWS.Script.queuedScripts[iQ].response = xhrObj.responseText; </li></ul><ul><li>EFWS.Script.injectScripts(); </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>eval(xhrObj.responseText); </li></ul><ul><li>if ( onload ) { </li></ul><ul><li>onload(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>xhrObj.open('GET', url, true); </li></ul><ul><li>xhrObj.send(''); </li></ul><ul><li>} </li></ul>process queue (next slide) or... eval now, call callback save response to queue add to queue (if bOrder)
    34. 35. EFWS.injectScripts <ul><li>// Process queued scripts to see if any are ready to inject. </li></ul><ul><li>injectScripts: function() { </li></ul><ul><li>var len = EFWS.Script.queuedScripts.length; </li></ul><ul><li>for ( var i = 0; i < len; i++ ) { </li></ul><ul><li>var qScript = EFWS.Script.queuedScripts[i]; </li></ul><ul><li>if ( ! qScript.done ) { </li></ul><ul><li>if ( ! qScript.response ) { </li></ul><ul><li>// STOP! need to wait for this response </li></ul><ul><li>break; </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>eval(qScript.response); </li></ul><ul><li>if ( qScript.onload ) { </li></ul><ul><li>qScript.onload(); </li></ul><ul><li>} </li></ul><ul><li>qScript.done = true; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>preserves external script order non-blocking works in all browsers couples with inlined code works with scripts across domains ready for this script, eval and call callback bail – need to wait to preserve order if not yet injected
    35. 36. technique 2: DOM Element and Doc Write Firefox & Opera – use Script DOM Element IE – use document.write Script Tag Safari, Chrome – no benefit; rely on Safari 4 and Chrome 2
    36. 37. EFWS.loadScripts <ul><li>loadScripts: function(aUrls, onload) { </li></ul><ul><li>// first pass: see if any of the scripts are on a different domain </li></ul><ul><li>var nUrls = aUrls.length; </li></ul><ul><li>var bDifferent = false; </li></ul><ul><li>for ( var i = 0; i < nUrls; i++ ) { </li></ul><ul><li>if ( EFWS.Script.differentDomain(aUrls[i]) ) { </li></ul><ul><li>bDifferent = true; </li></ul><ul><li>break; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>// pick the best loading function </li></ul><ul><li>var loadFunc = EFWS.Script.loadScriptXhrInjection; </li></ul><ul><li>if ( bDifferent ) { </li></ul><ul><li>if ( -1 != navigator.userAgent.indexOf('Firefox') || </li></ul><ul><li>-1 != navigator.userAgent.indexOf('Opera') ) { </li></ul><ul><li>loadFunc = EFWS.Script.loadScriptDomElement; </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>loadFunc = EFWS.Script.loadScriptDocWrite; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>// second pass: load the scripts </li></ul><ul><li>for ( var i = 0; i < nUrls; i++ ) { </li></ul><ul><li>loadFunc(aUrls[i], ( i+1 == nUrls ? onload : null ), true); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    37. 38. multiple scripts with dependencies <ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var aRaceConditions = [['couple-normal.php', 'Normal...]; </li></ul><ul><li>var aWorkarounds = [['hardcoded-callback.php', 'Hardcod...]; </li></ul><ul><li>var aMultipleScripts = [['managed-xhr.php', 'Managed XH...]; </li></ul><ul><li>var aLoadScripts = [['loadscript.php', 'loadScript'], ...]; </li></ul><ul><li>var aSubmenus = [[&quot;Race Conditions&quot;, aRaceConditions], ...]; </li></ul><ul><li>function init() { </li></ul><ul><li>EFWS.Menu.createTieredMenu('examplesbtn', aSubmenus); </li></ul><ul><li>} </li></ul><ul><li>EFWS.Script.loadScripts([&quot;menu.js&quot;, &quot;menutier.js&quot;], init); </li></ul><ul><li></script> </li></ul><ul><li>scripts on same domain: </li></ul><ul><ul><li>order preserved, no blocking </li></ul></ul><ul><li>scripts on different domain: </li></ul><ul><ul><li>order preserved: all </li></ul></ul><ul><ul><li>loads scripts in parallel: all except Saf3, Chr1 </li></ul></ul><ul><ul><li>load script and image in parallel: FF, Saf4, Chr2 </li></ul></ul>
    38. 39. asynchronous scripts wrap-up
    39. 40. case study: Google Analytics <ul><li>recommended pattern: 1 </li></ul><ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var gaJsHost = ((&quot;https:&quot; == document.location.protocol) ? &quot;https://ssl.&quot; : &quot;http://www.&quot;); </li></ul><ul><li>document.write(unescape(&quot;%3Cscript src='&quot; + gaJsHost + &quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&quot;)); </li></ul><ul><li></script> </li></ul><ul><li><script type=&quot;text/javascript&quot;> </li></ul><ul><li>var pageTracker = _gat._getTracker(&quot;UA-xxxxxx-x&quot;); </li></ul><ul><li>pageTracker._trackPageview(); </li></ul><ul><li></script> </li></ul><ul><li>document.write Script Tag approach blocks other resources </li></ul>1 http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55488
    40. 41. case study: dojox.analytics.Urchin 1 <ul><li>_loadGA: function(){ </li></ul><ul><li>var gaHost = (&quot;https:&quot; == document.location.protocol) ? </li></ul><ul><li>&quot;https://ssl.&quot; : &quot;http://www.&quot;; </li></ul><ul><li>dojo.create('script', { </li></ul><ul><li>src: gaHost + &quot;google-analytics.com/ga.js&quot; </li></ul><ul><li>}, dojo.doc.getElementsByTagName(&quot;head&quot;)[0]); </li></ul><ul><li>setTimeout(dojo.hitch(this, &quot;_checkGA&quot;), this.loadInterval); </li></ul><ul><li>}, </li></ul><ul><li>_checkGA: function(){ </li></ul><ul><li>setTimeout(dojo.hitch(this, !window[&quot;_gat&quot;] ? &quot;_checkGA&quot; : &quot;_gotGA&quot;), this.loadInterval); </li></ul><ul><li>}, </li></ul><ul><li>_gotGA: function(){ </li></ul><ul><li>this.tracker = _gat._getTracker(this.acct); ... </li></ul><ul><li>} </li></ul><ul><li>Script DOM Element approach </li></ul><ul><li>&quot;timer&quot; coupling technique (script onload better) </li></ul>1 http://docs.dojocampus.org/dojox/analytics/Urchin
    41. 42. asynchronous loading & coupling <ul><li>async technique: Script DOM Element </li></ul><ul><ul><li>easy, cross-browser </li></ul></ul><ul><ul><li>doesn't ensure script order </li></ul></ul><ul><li>coupling technique: script onload </li></ul><ul><ul><li>fairly easy, cross-browser </li></ul></ul><ul><ul><li>ensures execution order for external script and inlined code </li></ul></ul><ul><li>multiple interdependent external and inline scripts: </li></ul><ul><ul><li>much more complex (see hidden slides) </li></ul></ul><ul><ul><li>concatenate your external scripts into one! </li></ul></ul>
    42. 43. flushing the document early <ul><li>gotchas: </li></ul><ul><ul><li>PHP output_buffering – ob_flush() </li></ul></ul><ul><ul><li>Transfer-Encoding: chunked </li></ul></ul><ul><ul><li>gzip – Apache's DeflateBufferSize before 2.2.8 </li></ul></ul><ul><ul><li>proxies and anti-virus software </li></ul></ul><ul><ul><li>browsers – Safari (1K), Chrome (2K) </li></ul></ul><ul><li>other languages: </li></ul><ul><ul><li>$| or FileHandle autoflush (Perl), flush (Python), ios.flush (Ruby) </li></ul></ul>call PHP's flush() html image image script html image image script
    43. 44. flushing and domain blocking <ul><li>you might need to move flushed resources to a domain different from the HTML doc </li></ul>blocked by HTML document different domains html image image script html image image script
    44. 45. successful flushing <ul><li>Google Search </li></ul><ul><li>external resource downloaded early </li></ul><ul><li>content visible to the user </li></ul>http://www.google.com/images/nav_logo4.png google image image script image 204
    45. 46. performance analyzers (HPWS) YSlow Page Speed Pagetest VRTA neXpert combine JS & CSS X X X use CSS sprites X X use a CDN X X set Expires in the future X X X X X gzip text responses X X X X X put CSS at the top X X put JS at the bottom X avoid CSS expressions X X make JS & CSS external reduce DNS lookups X X minify JS X X X avoid redirects X X X X remove dupe scripts X remove ETags X X X
    46. 47. performance analyzers (EFWS) YSlow Page Speed Pagetest VRTA neXpert don't block UI thread split JS payload X load scripts async X inline JS b4 stylesheet X write efficient JS min. uncompressed size optimize images X X shard domains X X flush the document avoid iframes simplify CSS selectors X X
    47. 48. performance analyzers (other) YSlow Page Speed Pagetest VRTA neXpert use persistent conns X X X reduce cookies 2.0 X X X avoid net congestion X increase MTU, TCP win X avoid server congestion X remove unused CSS X specify image dims X use GET for Ajax 2.0 reduce DOM elements 2.0 avoid 404 errors 2.0 avoid Alpha filters 2.0 don't scale images 2.0 X optimize favicon 2.0
    48. 49. <ul><li>focus on the frontend </li></ul><ul><li>run YSlow ( http://developer.yahoo.com/yslow ) </li></ul><ul><li>and Page Speed! ( http://code.google.com/speed/page-speed/ ) </li></ul><ul><li>speed matters </li></ul>takeaways
    49. 50. <ul><li>Bing: </li></ul><ul><li>Yahoo: </li></ul><ul><li>Google: </li></ul><ul><li>AOL: </li></ul><ul><li>Shopzilla: </li></ul>impact on revenue 1 http://en.oreilly.com/velocity2009/public/schedule/detail/8523 2 http://www.slideshare.net/stoyan/yslow-20-presentation 3 http://en.oreilly.com/velocity2009/public/schedule/detail/7579 4 http://en.oreilly.com/velocity2009/public/schedule/detail/7709 +2000 ms  -4.3% revenue/user 1 +400 ms  -5-9% full-page traffic 2 +400 ms  -0.59% searches/user 1 fastest users  +50% page views 3 -5000 ms  +7-12% revenue 4
    50. 51. <ul><li>hardware – reduced load </li></ul><ul><ul><li>Shopzilla – 50% fewer servers </li></ul></ul><ul><li>bandwidth – reduced response size </li></ul>cost savings http://billwscott.com/share/presentations/2008/stanford/HPWP-RealWorld.pdf
    51. 52. <ul><li>if you want </li></ul><ul><ul><li>better user experience </li></ul></ul><ul><ul><li>more revenue </li></ul></ul><ul><ul><li>reduced operating costs </li></ul></ul><ul><li>the strategy is clear </li></ul><ul><li>Even Faster Web Sites </li></ul>
    52. 53. Steve Souders [email_address] http://stevesouders.com/docs/tae-20090914.ppt book signing immediately 3:30-3:50
    1. A particular slide catching your eye?

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

    ×