High Performance JavaScript (Amazon DevCon 2011)

9,397 views

Published on

Published in: Technology

High Performance JavaScript (Amazon DevCon 2011)

  1. 1. High Performance JavaScript Nicholas C. Zakas | Amazon DevCon | April 27, 2011
  2. 2. Whos this guy? Presentation Contributor, Architect Creator of YUI TestAuthor Lead Author Contributor Lead Author
  3. 3. @slicknet(Complaints: @robertduffy)
  4. 4. Does JavaScript performance matter?
  5. 5. After all, all browsers now have optimizing JavaScript enginesTracemonkey/ V8 Squirrelfish Chakra KarakanJaegarMonkey (all) (4+) (9+) (10.5+) (3.5+)
  6. 6. So our scripts are getting really, really fast
  7. 7. Old computers ran slow applications Small amounts of CPU power and memory
  8. 8. New computers are generally faster but slow applications still existMore CPU + more memory = less disciplined application development
  9. 9. Right???
  10. 10. Oh yeah, one more thing
  11. 11. http://jeftek.com/1942/motorola-xoom-sunspider-results/
  12. 12. Its still possible to write slowJavaScript on the new, faster JavaScript engines
  13. 13. JavaScript performance directlyaffects user experience
  14. 14. "Know the enemy and know yourself;in a hundred battles you will never be in peril." -Sun Tzu, The Art of War
  15. 15. The UI ThreadThe brains of the operation
  16. 16. The browser UI thread is responsible forboth UI updates and JavaScript execution Only one can happen at a time
  17. 17. Jobs for UI updates and JavaScript execution are added to a UI queue Each job must wait in line for its turn to execute
  18. 18. <button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button><script type="text/javascript">window.onload = function(){ document.getElementById("btn").onclick = function(){ //do something };};</script>
  19. 19. Before ClickUI Threadtime UI Queue
  20. 20. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  21. 21. When ClickedUI Thread UI Updatetime UI Queue onclick Draw down state UI Update
  22. 22. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  23. 23. When ClickedUI Thread UI Update onclick UI Updatetime UI Queue Draw up state
  24. 24. No UI updates while JavaScript is executing
  25. 25. JavaScript May Cause UI Update<button id="btn" style="font-size: 30px; padding: 0.5em 1em">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>
  26. 26. A UI update must use the latest info available
  27. 27. Long-running JavaScript = Unresponsive UI
  28. 28. Responsive UIUI Thread UI Update JavaScript UI Updatetime
  29. 29. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  30. 30. The longer JavaScript runs,the worse the user experience
  31. 31. The runaway script timer prevents JavaScript from running for too long Each browser imposes its own limit (except Opera)
  32. 32. Internet Explorer
  33. 33. Firefox
  34. 34. Safari
  35. 35. Chrome
  36. 36. Runaway Script Timer Limits• Internet Explorer: 5 million statements• Firefox: 10 seconds• Safari: 5 seconds• Chrome: Unknown, hooks into normal crash control mechanism• Opera: none
  37. 37. Does JIT compiling help?
  38. 38. Interpreted JavaScriptUI Thread Interprettime
  39. 39. JITed JavaScript (1st Run)UI ThreadCompile Executetime
  40. 40. JITed JavaScript (After 1st Run)UI Thread Executetime
  41. 41. How Long Is Too Long?“0.1 second [100ms] is about the limit forhaving the user feel that the system is reactinginstantaneously, meaning that no specialfeedback is necessary except to display theresult.” - Jakob Nielsen
  42. 42. Translation: No single JavaScript job shouldexecute for more than 100ms to ensure a responsive UI
  43. 43. Recommendation:Limit JavaScript execution to no more than 50ms measured on IE6 :)
  44. 44. Doing so makes your application awesome
  45. 45. Loadtime TechniquesDont let JavaScript interfere with page load performance
  46. 46. During page load, JavaScripttakes more time on the UI thread
  47. 47. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <script src="foo.js"></script> <p>See ya!</p></body></html>
  48. 48. ResultUI Thread UI Update JavaScript UI Updatetime
  49. 49. ResultUI Thread Hello world! foo.js See ya!time
  50. 50. ResultUI Thread Hello world! Download Parse Run See ya!time The UI thread needs to wait for the script to download, parse, and run before continuing
  51. 51. ResultUI Thread Hello world! Download Parse Run See ya! Variable ConstantDownload time takes the longest and is variable
  52. 52. Translation: The page doesnt render whileJavaScript is downloading, parsing, or executing during page load
  53. 53. <!doctype html><html><head> <title>Example</title></head><body> <script src="foo.js"></script> <p>Hello world!</p> <script src="bar.js"></script> <p>See ya!</p> <script src="baz.js"></script> <p>Uh oh!</p></body></html>
  54. 54. ResultUI Thread JavaScript UI Update JavaScript UI Update JavaScripttime The more scripts to download in between UI updates, the longer the page takes to render
  55. 55. Technique #1: Put scripts at the bottom
  56. 56. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <p>See ya!</p> <script src="foo.js"></script></body></html>
  57. 57. Put Scripts at BottomUI Thread UI Update UI Update JavaScript JavaScript JavaScripttime Even if there are multiple scripts, the page renders quickly
  58. 58. Technique #2: Combine JavaScript files
  59. 59. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <p>See ya!</p> <script src="foo.js"></script> <script src="bar.js"></script> <script src="baz.js"></script></body></html>
  60. 60. UI ThreadUI Update JavaScript JavaScript JavaScripttime Each script has overhead of downloading
  61. 61. UI ThreadUI Update JavaScripttime Combining all of the files limits the networkoverhead and gets scripts onto the page faster
  62. 62. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <p>See ya!</p> <script src="foo-and-bar-and-baz.js"></script></body></html>
  63. 63. Technique #3: Load scripts dynamically
  64. 64. Basic Techniquevar script = document.createElement("script"), body;script.type = "text/javascript";script.src = "foo.js";body.insertBefore(script, body.firstChild);Dynamically loaded scripts are non-blocking
  65. 65. Downloads no longer block the UI thread
  66. 66. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <script src="foo.js"></script> <p>See ya!</p></body></html>
  67. 67. Using HTML <script>UI Thread Hello world! Download Parse Run See ya!time
  68. 68. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <script> var script = document.createElement("script"), body = document.body; script.type = "text/javascript"; script.src = "foo.js"; body.insertBefore(script, body.firstChild); </script> <p>See ya!</p><!-- more content --></body></html>
  69. 69. Using Dynamic ScriptsUI Thread Hello world! See ya! Run UI Updatetime Download ParseOnly code execution happens on the UI thread, which means less blocking of UI updates
  70. 70. function loadScript(url, callback){ var script = document.createElement("script"), body = document.body; script.type = "text/javascript"; if (script.readyState){ //IE <= 8 script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function(){ callback(); }; } script.src = url; body.insertBefore(script, body.firstChild);}
  71. 71. UsageloadScript("foo.js", function(){ alert("Loaded!");});
  72. 72. Timing Note: Script execution begins immediatelyafter download and parse – timing of execution is not guaranteed
  73. 73. Using Dynamic ScriptsUI Thread Hello world! Run See ya! UI Updatetime Download ParseDepending on time to download and script size, execution may happen before next UI update
  74. 74. Technique #4: Defer scripts
  75. 75. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <script defer src="foo.js"></script> <p>See ya!</p> <!-- even more markup --></body></html>
  76. 76. Support for <script defer>3.5 7.0 5.0 4.0 ?
  77. 77. Deferred scripts begin to download immediately,but dont execute until all UI updates complete
  78. 78. Using <script defer>UI Thread Hello world! See ya! More UI More UI Runtime Download Parse Similar to dynamic script nodes, but with a guarantee that execution will happen last
  79. 79. Timing Note:Although scripts always execute after UI updates complete, the order ofmultiple <script defer> scripts is not guaranteed across browsers
  80. 80. Technique #5: Asynchronous scripts
  81. 81. <!doctype html><html><head> <title>Example</title></head><body> <p>Hello world!</p> <script async src="foo.js"></script> <p>See ya!</p> <!-- even more markup --></body></html>
  82. 82. Support for <script async>3.6 7.0 5.0 ? ?
  83. 83. Asynchronous scripts behave a lot like dynamic scripts
  84. 84. Using <script async>UI Thread Hello world! See ya! Run UI Updatetime Download ParseDownload begins immediately and execution is slotted in at first available spot
  85. 85. Note:Order of execution is explicitly notpreserved for asynchronous scripts
  86. 86. Runtime TechniquesWays to ensure JavaScript doesnt run away
  87. 87. function processArray(items, process, callback){ for (var i=0,len=items.length; i < len; i++){ process(items[i]); } callback();}
  88. 88. Technique #1: Timers
  89. 89. //create a new timer and delay by 500ms setTimeout(function(){ //code to execute here }, 500)setTimeout() schedules a function to be added to the UI queue after a delay
  90. 90. function timedProcessArray(items, process, callback){ //create a clone of the original var todo = items.concat(); setTimeout(function(){ var start = +new Date(); do { process(todo.shift()); } while (todo.length > 0 && (+new Date() - start < 50)); if (todo.length > 0){ setTimeout(arguments.callee, 25); } else { callback(items); } }, 25);}
  91. 91. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  92. 92. When ClickedUI Thread UI Updatetime UI Queue onclick UI Update
  93. 93. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  94. 94. When ClickedUI Thread UI Update onclick UI Updatetime UI Queue
  95. 95. After 25msUI Thread UI Update onclick UI Updatetime UI Queue JavaScript
  96. 96. After 25msUI Thread UI Update onclick UI Update JavaScripttime UI Queue
  97. 97. After Another 25msUI Thread UI Update onclick UI Update JavaScripttime UI Queue JavaScript
  98. 98. After Another 25msUI Thread UI Update onclick UI Update JavaScript JavaScripttime UI Queue
  99. 99. Technique #2: Web Workers
  100. 100. Web Workers● Asynchronous JavaScript execution● Execution happens outside of UI thread ● Not on the UI thread = no UI delays● Data-driven API ● Data is serialized when sending data into or out of Worker ● No access to DOM, BOM ● Completely separate execution environment
  101. 101. //in pagevar worker = new Worker("process.js");worker.onmessage = function(event){ useData(event.data);};worker.postMessage(values);//in process.jsself.onmessage = function(event){ var items = event.data; for (var i=0,len=items.length; i < len; i++){ process(items[i]); } self.postMessage(items);};
  102. 102. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  103. 103. When ClickedUI Thread UI Updatetime UI Queue onclick UI Update
  104. 104. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  105. 105. When ClickedUI Thread UI Update onclicktime Worker Thread UI Queue UI Update
  106. 106. When ClickedUI Thread UI Update onclick UI Updatetime Worker Thread UI Queue JavaScript
  107. 107. Worker Thread CompleteUI Thread UI Update onclick UI Updatetime UI Queue onmessage
  108. 108. Worker Thread CompleteUI Thread UI Update onclick UI Update onmessagetime UI Queue
  109. 109. Support for Web Workers3.5 4.0 4.0 ? 10.6
  110. 110. Repaint and ReflowHidden performance costs of common operations
  111. 111. Long UI updates =Unresponsive UI
  112. 112. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  113. 113. JavaScript can causelong UI updates by triggering repaint and reflow
  114. 114. A repaint occurs when a visual change doesnt require recalculation of layout Changes to visibility, colors (text/background), background images, etc.
  115. 115. Repaint<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button><script type="text/javascript">window.onload = function(){ document.getElementById("btn").onclick = function(){ this.style.color = "#ff0"; };};</script> Repaint!
  116. 116. A reflow occurs when a visual change requires a change in layoutInitial page load ▪ browser resize ▪ DOM structure change ▪ layout style change layout information retrieved
  117. 117. Reflow<button id="btn" style="font-size: 30px; padding: 0.5em 1em">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> Reflow!
  118. 118. Repaints and reflows are queued up as JavaScript executes and then executed in order
  119. 119. Reflowvar list = document.getElementsByClassName("items")[0], i, item;for (i=0; i < 10; i++){ item = document.createElement("li"); item.innerHTML = "Item #" + i; list.appendChild(item);} Reflow x 10!
  120. 120. Limiting repaints/reflowsimproves overall performance
  121. 121. Technique #1Perform DOM manipulations off-document
  122. 122. Off-Document Operations• Fast because theres no repaint/reflow• Techniques: – Remove element from the document, make changes, insert back into document – Set elements display to “none”, make changes, set display back to default – Build up DOM changes on a DocumentFragment then apply all at once
  123. 123. DocumentFragment• A document-like object• Not visually represented• Considered to be owned by the document from which it was created• When passed to appendChild(), appends all of its children rather than itself
  124. 124. DocumentFragmentvar list = document.getElementsByClassName("items")[0], fragment = document.createDocumentFragment(), i, item;for (i=0; i < 10; i++){ item = document.createElement("li"); item.innerHTML = "Item #" + i; fragment.appendChild(item);}list.appendChild(fragment); 1 Reflow
  125. 125. Technique #2Group Style Changes
  126. 126. Repaint! Reflow!element.style.color = "red";element.style.height = "100px"; Reflow!element.style.fontSize = "25px";element.style.backgroundColor = "white"; Repaint!
  127. 127. Grouping Style Changes.active { color: red; height: 100px; fontSize: 25px; background-color: white;}element.className = "active"; Reflow!
  128. 128. Grouping Style Changesvar item = document.getElementById("myItem");item.style.cssText = "color:red;height:100px;" + "font-size:25px;background-color: white"); Reflow!
  129. 129. Technique #3Avoid Accidental Reflow
  130. 130. Accidental Reflowelement.width = "100px";var width = element.offsetWidth; Reflow!
  131. 131. What to do?• Minimize access to layout information – offsetTop, offsetLeft, offsetWidth, offsetHeight – scrollTop, scrollLeft, scrollWidth, scrollHeight – clientTop, clientLeft, clientWidth, clientHeight – Most computed styles• If a value is used more than once, store in local variable
  132. 132. Does hardware acceleration help?
  133. 133. Traditional RenderingUI Thread Compositing Drawingtime
  134. 134. Hardware AccelerationUI Thread Prep Waittime Rendering info Signal complete Compositing Drawing GPU
  135. 135. Recap
  136. 136. The browser UI thread is responsible forboth UI updates and JavaScript execution Only one can happen at a time
  137. 137. Responsive UIUI Thread UI Update JavaScript UI Updatetime
  138. 138. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  139. 139. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  140. 140. Avoid Slow Loading JavaScript• Put scripts at the bottom• Concatenate scripts into as few files as possible• Choose the right way to load your scripts – Dynamically created scripts – Deferred scripts – Asynchronous scripts
  141. 141. Avoid Slow JavaScript• Dont allow JavaScript to execute for more than 50ms• Break up long JavaScript processes using: – Timers – Web Workers
  142. 142. Avoid Long UI Updates• Be careful of repaint and reflow• Perform complex DOM operations off- document – Remove elements and re-add them – Use DocumentFragment objects• Group style changes together• Avoid accidental reflow
  143. 143. Dont be horrible
  144. 144. Do be awesome
  145. 145. The End
  146. 146. Etcetera• My blog: www.nczonline.net• Twitter: @slicknet• These Slides: http://slideshare.net/nzakas/
  147. 147. Creative Commons Images Used• http://www.flickr.com/photos/lrargerich/3115367361/• http://www.flickr.com/photos/hippie/2406411610/• http://www.flickr.com/photos/55733754@N00/3325000738/• http://www.flickr.com/photos/eurleif/255241547/• http://www.flickr.com/photos/off_the_wall/3444915939/• http://www.flickr.com/photos/wwarby/3296379139/• http://www.flickr.com/photos/derekgavey/4358797365/• http://www.flickr.com/photos/mulad/286641998/• http://www.flickr.com/photos/torley/2361164281/• http://www.flickr.com/photos/ottoman42/455242/• http://www.flickr.com/photos/goincase/3843348908/

×