High Performance JavaScript (Amazon DevCon 2011)

  • 7,754 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
7,754
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
166
Comments
0
Likes
22

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. High Performance JavaScript Nicholas C. Zakas | Amazon DevCon | April 27, 2011
  • 2. Whos this guy? Presentation Contributor, Architect Creator of YUI TestAuthor Lead Author Contributor Lead Author
  • 3. @slicknet(Complaints: @robertduffy)
  • 4. Does JavaScript performance matter?
  • 5. After all, all browsers now have optimizing JavaScript enginesTracemonkey/ V8 Squirrelfish Chakra KarakanJaegarMonkey (all) (4+) (9+) (10.5+) (3.5+)
  • 6. So our scripts are getting really, really fast
  • 7. Old computers ran slow applications Small amounts of CPU power and memory
  • 8. New computers are generally faster but slow applications still existMore CPU + more memory = less disciplined application development
  • 9. Right???
  • 10. Oh yeah, one more thing
  • 11. http://jeftek.com/1942/motorola-xoom-sunspider-results/
  • 12. Its still possible to write slowJavaScript on the new, faster JavaScript engines
  • 13. JavaScript performance directlyaffects user experience
  • 14. "Know the enemy and know yourself;in a hundred battles you will never be in peril." -Sun Tzu, The Art of War
  • 15. The UI ThreadThe brains of the operation
  • 16. The browser UI thread is responsible forboth UI updates and JavaScript execution Only one can happen at a time
  • 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. <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. Before ClickUI Threadtime UI Queue
  • 20. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  • 21. When ClickedUI Thread UI Updatetime UI Queue onclick Draw down state UI Update
  • 22. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  • 23. When ClickedUI Thread UI Update onclick UI Updatetime UI Queue Draw up state
  • 24. No UI updates while JavaScript is executing
  • 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. A UI update must use the latest info available
  • 27. Long-running JavaScript = Unresponsive UI
  • 28. Responsive UIUI Thread UI Update JavaScript UI Updatetime
  • 29. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  • 30. The longer JavaScript runs,the worse the user experience
  • 31. The runaway script timer prevents JavaScript from running for too long Each browser imposes its own limit (except Opera)
  • 32. Internet Explorer
  • 33. Firefox
  • 34. Safari
  • 35. Chrome
  • 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. Does JIT compiling help?
  • 38. Interpreted JavaScriptUI Thread Interprettime
  • 39. JITed JavaScript (1st Run)UI ThreadCompile Executetime
  • 40. JITed JavaScript (After 1st Run)UI Thread Executetime
  • 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. Translation: No single JavaScript job shouldexecute for more than 100ms to ensure a responsive UI
  • 43. Recommendation:Limit JavaScript execution to no more than 50ms measured on IE6 :)
  • 44. Doing so makes your application awesome
  • 45. Loadtime TechniquesDont let JavaScript interfere with page load performance
  • 46. During page load, JavaScripttakes more time on the UI thread
  • 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. ResultUI Thread UI Update JavaScript UI Updatetime
  • 49. ResultUI Thread Hello world! foo.js See ya!time
  • 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. ResultUI Thread Hello world! Download Parse Run See ya! Variable ConstantDownload time takes the longest and is variable
  • 52. Translation: The page doesnt render whileJavaScript is downloading, parsing, or executing during page load
  • 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. 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. Technique #1: Put scripts at the bottom
  • 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. Put Scripts at BottomUI Thread UI Update UI Update JavaScript JavaScript JavaScripttime Even if there are multiple scripts, the page renders quickly
  • 58. Technique #2: Combine JavaScript files
  • 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. UI ThreadUI Update JavaScript JavaScript JavaScripttime Each script has overhead of downloading
  • 61. UI ThreadUI Update JavaScripttime Combining all of the files limits the networkoverhead and gets scripts onto the page faster
  • 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. Technique #3: Load scripts dynamically
  • 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. Downloads no longer block the UI thread
  • 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. Using HTML <script>UI Thread Hello world! Download Parse Run See ya!time
  • 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. 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. 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. UsageloadScript("foo.js", function(){ alert("Loaded!");});
  • 72. Timing Note: Script execution begins immediatelyafter download and parse – timing of execution is not guaranteed
  • 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. Technique #4: Defer scripts
  • 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. Support for <script defer>3.5 7.0 5.0 4.0 ?
  • 77. Deferred scripts begin to download immediately,but dont execute until all UI updates complete
  • 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. Timing Note:Although scripts always execute after UI updates complete, the order ofmultiple <script defer> scripts is not guaranteed across browsers
  • 80. Technique #5: Asynchronous scripts
  • 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. Support for <script async>3.6 7.0 5.0 ? ?
  • 83. Asynchronous scripts behave a lot like dynamic scripts
  • 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. Note:Order of execution is explicitly notpreserved for asynchronous scripts
  • 86. Runtime TechniquesWays to ensure JavaScript doesnt run away
  • 87. function processArray(items, process, callback){ for (var i=0,len=items.length; i < len; i++){ process(items[i]); } callback();}
  • 88. Technique #1: Timers
  • 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. 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. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  • 92. When ClickedUI Thread UI Updatetime UI Queue onclick UI Update
  • 93. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  • 94. When ClickedUI Thread UI Update onclick UI Updatetime UI Queue
  • 95. After 25msUI Thread UI Update onclick UI Updatetime UI Queue JavaScript
  • 96. After 25msUI Thread UI Update onclick UI Update JavaScripttime UI Queue
  • 97. After Another 25msUI Thread UI Update onclick UI Update JavaScripttime UI Queue JavaScript
  • 98. After Another 25msUI Thread UI Update onclick UI Update JavaScript JavaScripttime UI Queue
  • 99. Technique #2: Web Workers
  • 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. //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. When ClickedUI Threadtime UI Queue UI Update onclick UI Update
  • 103. When ClickedUI Thread UI Updatetime UI Queue onclick UI Update
  • 104. When ClickedUI Thread UI Update onclicktime UI Queue UI Update
  • 105. When ClickedUI Thread UI Update onclicktime Worker Thread UI Queue UI Update
  • 106. When ClickedUI Thread UI Update onclick UI Updatetime Worker Thread UI Queue JavaScript
  • 107. Worker Thread CompleteUI Thread UI Update onclick UI Updatetime UI Queue onmessage
  • 108. Worker Thread CompleteUI Thread UI Update onclick UI Update onmessagetime UI Queue
  • 109. Support for Web Workers3.5 4.0 4.0 ? 10.6
  • 110. Repaint and ReflowHidden performance costs of common operations
  • 111. Long UI updates =Unresponsive UI
  • 112. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  • 113. JavaScript can causelong UI updates by triggering repaint and reflow
  • 114. A repaint occurs when a visual change doesnt require recalculation of layout Changes to visibility, colors (text/background), background images, etc.
  • 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. 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. 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. Repaints and reflows are queued up as JavaScript executes and then executed in order
  • 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. Limiting repaints/reflowsimproves overall performance
  • 121. Technique #1Perform DOM manipulations off-document
  • 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. 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. 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. Technique #2Group Style Changes
  • 126. Repaint! Reflow!element.style.color = "red";element.style.height = "100px"; Reflow!element.style.fontSize = "25px";element.style.backgroundColor = "white"; Repaint!
  • 127. Grouping Style Changes.active { color: red; height: 100px; fontSize: 25px; background-color: white;}element.className = "active"; Reflow!
  • 128. Grouping Style Changesvar item = document.getElementById("myItem");item.style.cssText = "color:red;height:100px;" + "font-size:25px;background-color: white"); Reflow!
  • 129. Technique #3Avoid Accidental Reflow
  • 130. Accidental Reflowelement.width = "100px";var width = element.offsetWidth; Reflow!
  • 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. Does hardware acceleration help?
  • 133. Traditional RenderingUI Thread Compositing Drawingtime
  • 134. Hardware AccelerationUI Thread Prep Waittime Rendering info Signal complete Compositing Drawing GPU
  • 135. Recap
  • 136. The browser UI thread is responsible forboth UI updates and JavaScript execution Only one can happen at a time
  • 137. Responsive UIUI Thread UI Update JavaScript UI Updatetime
  • 138. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  • 139. Unresponsive UIUI Thread UI Update JavaScript UI Updatetime
  • 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. Avoid Slow JavaScript• Dont allow JavaScript to execute for more than 50ms• Break up long JavaScript processes using: – Timers – Web Workers
  • 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. Dont be horrible
  • 144. Do be awesome
  • 145. The End
  • 146. Etcetera• My blog: www.nczonline.net• Twitter: @slicknet• These Slides: http://slideshare.net/nzakas/
  • 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/