High-Performance JavaScript:   Why Everything You’ve Been Taught is Wrong <ul><li>Joseph Smarr </li></ul><ul><li>Plaxo, In...
About me <ul><li>Chief Platform Architect at Plaxo </li></ul><ul><ul><li>First employee (March 2002) </li></ul></ul><ul><u...
About Plaxo <ul><li>Smart Address Book </li></ul><ul><ul><li>Syncs address book and calendar with lots of places </li></ul...
Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop  </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar <...
Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop  </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar <...
Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop  </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar <...
Looks great…but it almost didn’t ship! <ul><li>Spring 06:  “Let’s really push the envelope for Plaxo 3.0” </li></ul><ul><l...
Where did we go wrong?? <ul><li>Didn’t take performance seriously from day one </li></ul><ul><li>Didn’t think the browser’...
Why Everything You’ve Been Taught is Wrong <ul><li>AJAX euphoria </li></ul><ul><ul><li>Web browsers can be made to do anyt...
Why High-Performance JavaScript Matters <ul><li>Everyone is amazed by fast apps </li></ul><ul><ul><li>It hardly matters wh...
The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic </li></ul><u...
The High-Performance JS Mantra <ul><li>Be Lazy:  Nothing is faster than doing nothing </li></ul><ul><li>Be Responsive </li...
Write less code  <ul><li>Initial  parsing  of JavaScript is often a major bottleneck </li></ul><ul><ul><li>No JIT, no cach...
Total code size of some AJAX apps
Write less code <ul><li>Minimize the JavaScript code you send down </li></ul><ul><ul><li>Minify = good, obfuscate = not mu...
Load JavaScript on-demand <ul><li>Once you’ve written less code, load it only as-needed </li></ul><ul><ul><li>Break into c...
Draw UI as late as possible <ul><li>Draw less DOM = faster to draw, browser less saturated </li></ul><ul><li>Never pre-dra...
<ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
<ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
<ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
<ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
<ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
How to Be Lazy  <ul><li>Write less code! </li></ul><ul><li>Load JS on-demand </li></ul><ul><li>Draw UI as late as possible...
The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive:   Jump when the user says jump </li></ul><...
Minimize initial perceived load time <ul><li>Put CSS at the top of your page and JS at the bottom </li></ul><ul><li>Draw m...
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
<ul><ul><li>Load your app in stages </li></ul></ul>
Yield early and often <ul><li>Always want to show a quick response acknowledgement </li></ul><ul><ul><li>But browser often...
Cache backend responses <ul><li>All data requests should go through data-manager code </li></ul><ul><ul><li>Request as nee...
How to Be Responsive  <ul><li>Minimize initial perceived loading time </li></ul><ul><li>Yield early and often for responsi...
The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic:   Don’t mak...
Play to the browser’s strengths <ul><li>Avoid DOM manipulation; use  innerHTML  and  array.join(“”) </li></ul><ul><li>Avoi...
Cheat when you can / should <ul><li>Use global functions or IDs when reasonable </li></ul><ul><ul><li>Finding by class / a...
Inline initial API calls & HTML <ul><li>Tempting to load blank page and do everything in JavaScript </li></ul><ul><ul><li>...
How to Be Pragmatic  <ul><li>Play to the browser’s strengths </li></ul><ul><li>Cheat when you can / should </li></ul><ul><...
The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic </li></ul><u...
Profile like crazy <ul><li>Bottlenecks abound and are usually not obvious </li></ul><ul><ul><li>Use firebug’s profiler (Jo...
Firebug is your friend
Consider performance from day one <ul><li>Apps get slow when you make them do many / slow things! </li></ul><ul><li>Consid...
<ul><li>Building high-performance apps requires the right attitude </li></ul><ul><ul><li>Must consider and prioritize spee...
How to Be Vigilant  <ul><li>Profile like crazy </li></ul><ul><li>Consider performance from day one </li></ul><ul><li>Get y...
Conclusion:  Avoid making the same mistakes we did <ul><li>Make the browser happy … and it will make you happy </li></ul><...
Just Remember: Everything You’ve Been Taught is Wrong <ul><li>Think about performance — early and often </li></ul><ul><li>...
Upcoming SlideShare
Loading in …5
×

Smarr Oscon 2007

1,630 views
1,555 views

Published on

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,630
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
20
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide
  • Smarr Oscon 2007

    1. 1. High-Performance JavaScript: Why Everything You’ve Been Taught is Wrong <ul><li>Joseph Smarr </li></ul><ul><li>Plaxo, Inc. </li></ul>
    2. 2. About me <ul><li>Chief Platform Architect at Plaxo </li></ul><ul><ul><li>First employee (March 2002) </li></ul></ul><ul><ul><li>Architect and lead developer for Plaxo Online </li></ul></ul><ul><li>Abusing web browsers since 1993 (Mosaic) </li></ul><ul><ul><li>Plaxo Online 2.0 (AJAX via iframes in 2004) </li></ul></ul><ul><ul><li>JavaScript Wormhole (OSCON 06) </li></ul></ul>http://JosephSmarr.com
    3. 3. About Plaxo <ul><li>Smart Address Book </li></ul><ul><ul><li>Syncs address book and calendar with lots of places </li></ul></ul><ul><ul><li>User updates their contact info  you get it automatically </li></ul></ul><ul><li>Founded in 2002, ~50 employees, 15M+ users </li></ul><ul><ul><li>Backed by Sequoia, Ram Shriram, Tim Koogle, et al </li></ul></ul>http://www.plaxo.com
    4. 4. Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar </li></ul><ul><li>Tasks </li></ul><ul><li>Notes </li></ul><ul><li>Sync dashboard </li></ul><ul><li>Pulse </li></ul><ul><li>Profile / settings </li></ul>
    5. 5. Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar </li></ul><ul><li>Tasks </li></ul><ul><li>Notes </li></ul><ul><li>Sync dashboard </li></ul><ul><li>Pulse </li></ul><ul><li>Profile / settings </li></ul>
    6. 6. Plaxo Online AJAX Desktop beta.plaxo.com <ul><li>Flexible desktop </li></ul><ul><li>Contacts </li></ul><ul><li>Calendar </li></ul><ul><li>Tasks </li></ul><ul><li>Notes </li></ul><ul><li>Sync dashboard </li></ul><ul><li>Pulse </li></ul><ul><li>Profile / settings </li></ul>
    7. 7. Looks great…but it almost didn’t ship! <ul><li>Spring 06: “Let’s really push the envelope for Plaxo 3.0” </li></ul><ul><li>Summer 06: “Wow, these are great UI ideas, keep em coming” </li></ul><ul><li>Fall 06: “Let’s put 7 great web devs full time on this”’ </li></ul><ul><li>Winter 06: “Ok, we built a ton…now let’s optimize it, no problem” </li></ul><ul><li>March 07: “Uh oh, making it fast is way harder than we thought” </li></ul><ul><li>April 07: “We can’t ship this as is—do we need to start over?!?” </li></ul><ul><li>June 07: “After a heroic effort, it’s just barely fast enough (phew!)” </li></ul>
    8. 8. Where did we go wrong?? <ul><li>Didn’t take performance seriously from day one </li></ul><ul><li>Didn’t think the browser’s limitations were significant </li></ul><ul><li>Didn’t use the app daily as we were developing it </li></ul><ul><li>Didn’t push back on feature requests for performance </li></ul><ul><li>Didn’t value perceived performance / responsiveness </li></ul><ul><li>…overcoming these challenges required unlearning a lot of standard assumptions about building software… </li></ul>
    9. 9. Why Everything You’ve Been Taught is Wrong <ul><li>AJAX euphoria </li></ul><ul><ul><li>Web browsers can be made to do anything now! </li></ul></ul><ul><ul><li>Use desktop / OOP programming style </li></ul></ul><ul><li>Why it’s wrong </li></ul><ul><ul><li>Browsers are being pushed beyond their comfort zone </li></ul></ul><ul><ul><li>JavaScript code is parsed & interpreted every time  cost per line of source code </li></ul></ul>
    10. 10. Why High-Performance JavaScript Matters <ul><li>Everyone is amazed by fast apps </li></ul><ul><ul><li>It hardly matters what else they do! </li></ul></ul><ul><li>Everyone hates slow apps </li></ul><ul><ul><li>It hardly matters what else they do… </li></ul></ul><ul><li>AJAX was supposed to be all about responsiveness!! </li></ul><ul><li>Having tried and almost failed, we now have a mantra: </li></ul>
    11. 11. The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic </li></ul><ul><li>Be Vigilant </li></ul>
    12. 12. The High-Performance JS Mantra <ul><li>Be Lazy: Nothing is faster than doing nothing </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic </li></ul><ul><li>Be Vigilant </li></ul>
    13. 13. Write less code <ul><li>Initial parsing of JavaScript is often a major bottleneck </li></ul><ul><ul><li>No JIT, no cached object code, interpreted every time </li></ul></ul><ul><ul><li>Parse time is non-linear in the size of total JavaScript? </li></ul></ul><ul><li>Can’t rely on browser caching to excuse large code size </li></ul><ul><ul><li>Yahoo study: surprising number of hits with empty cache </li></ul></ul><ul><ul><li>Frequent code releases  frequently need to re-download </li></ul></ul><ul><li>More code = more to download, execute, maintain, etc. </li></ul><ul><ul><li>Ideal for large AJAX apps is <500K JS uncompressed </li></ul></ul>Be Lazy: Nothing is faster than doing nothing
    14. 14. Total code size of some AJAX apps
    15. 15. Write less code <ul><li>Minimize the JavaScript code you send down </li></ul><ul><ul><li>Minify = good, obfuscate = not much better </li></ul></ul><ul><ul><li>Strip debug / logging lines (don’t just set log-level = 0) </li></ul></ul><ul><ul><li>Remove unnecessary OOP boilerplate </li></ul></ul><ul><ul><ul><li>Get/Set functions don’t actually protect member vars! etc. </li></ul></ul></ul><ul><li>Minimize dependency on third-party library code </li></ul><ul><ul><li>Lots of extra code comes along that you don’t need </li></ul></ul><ul><ul><li>Libraries solve more general problems  use like scaffolding </li></ul></ul>Be Lazy: Nothing is faster than doing nothing
    16. 16. Load JavaScript on-demand <ul><li>Once you’ve written less code, load it only as-needed </li></ul><ul><ul><li>Break into classes / modules; use require / provide (ala dojo) </li></ul></ul><ul><li>Bundle classes into packages to minimize server round-trips </li></ul><ul><ul><li>Packages should ignore pre-loaded dependencies </li></ul></ul><ul><ul><li>Tradeoff of downloading shared code twice vs. multiple round trips (e.g. for common widgets) </li></ul></ul><ul><li>Build packages with error-handler hook for development </li></ul><ul><ul><li>Will re-build from source every time if you don’t write </li></ul></ul>Be Lazy: Nothing is faster than doing nothing “ I work hard at being lazy” Ryan “Roger” Moore
    17. 17. Draw UI as late as possible <ul><li>Draw less DOM = faster to draw, browser less saturated </li></ul><ul><li>Never pre-draw hidden UI if you can avoid it </li></ul><ul><li>Cache previously drawn HTML when appropriate </li></ul><ul><ul><li>But have to know when to invalidate the cache </li></ul></ul><ul><li>Don’t keep hidden UI up-to-date behind the scenes </li></ul><ul><ul><li>Just re-draw next time you show it (simpler, one-time cost) </li></ul></ul><ul><li>Consider re-drawing vs. partial dynamic UI updates </li></ul><ul><ul><li>Redraw is often faster / easier / less code </li></ul></ul>Be Lazy: Nothing is faster than doing nothing
    18. 18. <ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
    19. 19. <ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
    20. 20. <ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
    21. 21. <ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
    22. 22. <ul><ul><li>Never pre-draw hidden UI </li></ul></ul>
    23. 23. How to Be Lazy <ul><li>Write less code! </li></ul><ul><li>Load JS on-demand </li></ul><ul><li>Draw UI as late as possible </li></ul>Be Lazy: Nothing is faster than doing nothing
    24. 24. The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive: Jump when the user says jump </li></ul><ul><li>Be Pragmatic </li></ul><ul><li>Be Vigilant </li></ul>
    25. 25. Minimize initial perceived load time <ul><li>Put CSS at the top of your page and JS at the bottom </li></ul><ul><li>Draw major placeholder UI with “loading…” first </li></ul><ul><li>Load / draw your app in stages (lazy, on-demand) </li></ul>Be Responsive: Jump when the user says jump
    26. 26. <ul><ul><li>Load your app in stages </li></ul></ul>
    27. 27. <ul><ul><li>Load your app in stages </li></ul></ul>
    28. 28. <ul><ul><li>Load your app in stages </li></ul></ul>
    29. 29. <ul><ul><li>Load your app in stages </li></ul></ul>
    30. 30. <ul><ul><li>Load your app in stages </li></ul></ul>
    31. 31. <ul><ul><li>Load your app in stages </li></ul></ul>
    32. 32. <ul><ul><li>Load your app in stages </li></ul></ul>
    33. 33. Yield early and often <ul><li>Always want to show a quick response acknowledgement </li></ul><ul><ul><li>But browser often doesn’t update UI until your code returns! </li></ul></ul><ul><li>Solution: do minimum work, use setTimeout(0) to yield </li></ul><ul><ul><li>Use closures to chain state together with periodic pauses </li></ul></ul><ul><ul><li>Draw UI progressively, with loading messages as needed </li></ul></ul><ul><ul><li>Use onmousedown instead of onclick (~100msec faster!) </li></ul></ul><ul><ul><li>Demo: http://josephsmarr.com/oscon-js/yield.html </li></ul></ul>Be Responsive: Jump when the user says jump
    34. 34. Cache backend responses <ul><li>All data requests should go through data-manager code </li></ul><ul><ul><li>Request as needed and cache results for subsequent asks </li></ul></ul><ul><ul><li>Requesting code always assumes async response </li></ul></ul><ul><li>Use range caches  only fill in missing pieces </li></ul><ul><ul><li>Ideal for partial views into long lists of data </li></ul></ul><ul><li>Balance local updates vs. re-fetching from APIs </li></ul><ul><ul><li>Do the easy cases, but beware of too much update code </li></ul></ul><ul><ul><li>Worst case = trash cache and re-fetch = first-time case </li></ul></ul>Be Responsive: Jump when the user says jump “ Data structures and AJAX—together at last!” Glenn “Fiddich” Dixon
    35. 35. How to Be Responsive <ul><li>Minimize initial perceived loading time </li></ul><ul><li>Yield early and often for responsive UI </li></ul><ul><li>Cache API responses with data-manager layer </li></ul>Be Responsive: Jump when the user says jump
    36. 36. The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic: Don’t make things even harder </li></ul><ul><li>Be Vigilant </li></ul>
    37. 37. Play to the browser’s strengths <ul><li>Avoid DOM manipulation; use innerHTML and array.join(“”) </li></ul><ul><li>Avoid dynamic CSS-class definitions & CSS math </li></ul><ul><li>Avoid reflow when possible (esp. manually on browser resize) </li></ul><ul><li>Avoid memory allocation (e.g. string-splitting) </li></ul><ul><li>Do DOM manipulation off-DOM, then re-insert at the end </li></ul>Be Pragmatic: Don’t make things even harder
    38. 38. Cheat when you can / should <ul><li>Use global functions or IDs when reasonable </li></ul><ul><ul><li>Finding by class / attaching event handlers is slow </li></ul></ul><ul><ul><li>Protect modularity only when needed (e.g. widgets) </li></ul></ul><ul><li>Directly attach onclick , etc. handlers instead of using event listeners where appropriate </li></ul><ul><li>Use fastest find-elems available when you need to scan the DOM (don’t rely on general-purpose code) </li></ul>Be Pragmatic: Don’t make things even harder
    39. 39. Inline initial API calls & HTML <ul><li>Tempting to load blank page and do everything in JavaScript </li></ul><ul><ul><li>Have to redraw UI dynamically; don’t want two copies of UI code </li></ul></ul><ul><li>Problem: initial load is usually too slow </li></ul><ul><ul><li>Too many round-trips to the server; too long before initial UI shows up </li></ul></ul><ul><li>Solution: if you have to do it every time, do it statically </li></ul><ul><ul><li>Save out initial API responses in web page </li></ul></ul><ul><ul><li>Use data-manager to hide pre-fetching (can change your mind later) </li></ul></ul><ul><ul><li>Download initial HTML in web page </li></ul></ul>Be Pragmatic: Don’t make things even harder
    40. 40. How to Be Pragmatic <ul><li>Play to the browser’s strengths </li></ul><ul><li>Cheat when you can / should </li></ul><ul><li>Inline initial API calls / HTML for faster load time </li></ul>Be Pragmatic: Don’t make things even harder
    41. 41. The High-Performance JS Mantra <ul><li>Be Lazy </li></ul><ul><li>Be Responsive </li></ul><ul><li>Be Pragmatic </li></ul><ul><li>Be Vigilant: Only you can prevent slow web apps </li></ul>
    42. 42. Profile like crazy <ul><li>Bottlenecks abound and are usually not obvious </li></ul><ul><ul><li>Use firebug’s profiler (Joe Hewitt, you rule!  ) </li></ul></ul><ul><ul><li>Use timestamp diffs and alerts </li></ul></ul><ul><ul><li>Comment-out blocks of code </li></ul></ul><ul><li>Measure with a consistent environment </li></ul><ul><ul><li>Browsers bog down  always restart first </li></ul></ul><ul><ul><li>Try multiple runs and average (and don’t forget the cache) </li></ul></ul>Be Vigilant: Only you can prevent slow web apps
    43. 43. Firebug is your friend
    44. 44. Consider performance from day one <ul><li>Apps get slow when you make them do many / slow things! </li></ul><ul><li>Consider how much code / work is needed for each feature </li></ul><ul><ul><li>Is it making the browser work against the grain? </li></ul></ul><ul><ul><li>What else is suffering for this feature? Is it worth it? </li></ul></ul><ul><li>Make sure everyone remembers how important speed is </li></ul>Be Vigilant: Only you can prevent slow web apps
    45. 45. <ul><li>Building high-performance apps requires the right attitude </li></ul><ul><ul><li>Must consider and prioritize speed in every decision </li></ul></ul><ul><li>Ask “what features can I add within this size / speed?” vs. “how small / fast can I get this set of features?” </li></ul><ul><ul><li>I had to learn this the hard way (Plaxo 3.0 almost didn’t ship!) </li></ul></ul>Get your priorities straight Be Vigilant: Only you can prevent slow web apps “ Performance first, features second!” Todd & Cam
    46. 46. How to Be Vigilant <ul><li>Profile like crazy </li></ul><ul><li>Consider performance from day one </li></ul><ul><li>Get your priorities straight </li></ul>Be Vigilant: Only you can prevent slow web apps
    47. 47. Conclusion: Avoid making the same mistakes we did <ul><li>Make the browser happy … and it will make you happy </li></ul><ul><li>Web browsers are more like mobile phones than desktops </li></ul><ul><ul><li>Limited, flimsy, temperamental platform being stretched beyond its initial design goals </li></ul></ul><ul><ul><li>But everyone’s got one, so it’s still the best place to be </li></ul></ul><ul><li>Don’t push the limits unless you have to </li></ul><ul><ul><li>Often, small quick-loading pages with AJAX interactions is best </li></ul></ul><ul><ul><li>Sometimes you really do need rich, interactive controls </li></ul></ul>
    48. 48. Just Remember: Everything You’ve Been Taught is Wrong <ul><li>Think about performance — early and often </li></ul><ul><li>Write as little code as you need — each line has a cost </li></ul><ul><li>Do what the browser wants (whenever possible) </li></ul><ul><li>Remember the high-performance JavaScript mantra: </li></ul><ul><ul><li>Be lazy </li></ul></ul><ul><ul><li>Be responsive </li></ul></ul><ul><ul><li>Be pragmatic </li></ul></ul><ul><ul><li>Be vigilant </li></ul></ul>http://JosephSmarr.com

    ×