HighPerformance JavaScript: Why Everything Youve Been Taught is Wrong PowerPoint PPT Presentation

presentation player overlay
About This Presentation
Transcript and Presenter's Notes

Title: HighPerformance JavaScript: Why Everything Youve Been Taught is Wrong


1
High-Performance JavaScript Why Everything
Youve Been Taught is Wrong
  • Joseph Smarr
  • Plaxo, Inc.

2
About me
  • Chief Platform Architect at Plaxo
  • First employee (March 2002)
  • Architect and lead developer for Plaxo Online
  • Abusing web browsers since 1993 (Mosaic)
  • Plaxo Online 2.0 (AJAX via iframes in 2004)
  • JavaScript Wormhole (OSCON 06)

http//JosephSmarr.com
3
About Plaxo
  • Smart Address Book
  • Syncs address book and calendar with lots of
    places
  • User updates their contact info ? you get it
    automatically
  • Founded in 2002, 50 employees, 15M users
  • Backed by Sequoia, Ram Shriram, Tim Koogle, et al

http//www.plaxo.com
4
Plaxo Online AJAX Desktop beta.plaxo.com
  • Flexible desktop
  • Contacts
  • Calendar
  • Tasks
  • Notes
  • Sync dashboard
  • Pulse
  • Profile / settings

5
Plaxo Online AJAX Desktop beta.plaxo.com
  • Flexible desktop
  • Contacts
  • Calendar
  • Tasks
  • Notes
  • Sync dashboard
  • Pulse
  • Profile / settings

6
Plaxo Online AJAX Desktop beta.plaxo.com
  • Flexible desktop
  • Contacts
  • Calendar
  • Tasks
  • Notes
  • Sync dashboard
  • Pulse
  • Profile / settings

7
Looks greatbut it almost didnt ship!
  • Spring 06 Lets really push the envelope for
    Plaxo 3.0
  • Summer 06 Wow, these are great UI ideas, keep
    em coming
  • Fall 06 Lets put 7 great web devs full time on
    this
  • Winter 06 Ok, we built a tonnow lets optimize
    it, no problem
  • March 07 Uh oh, making it fast is way harder
    than we thought
  • April 07 We cant ship this as isdo we need to
    start over?!?
  • June 07 After a heroic effort, its just barely
    fast enough (phew!)

8
Where did we go wrong??
  • Didnt take performance seriously from day one
  • Didnt think the browsers limitations were
    significant
  • Didnt use the app daily as we were developing it
  • Didnt push back on feature requests for
    performance
  • Didnt value perceived performance /
    responsiveness
  • overcoming these challenges required unlearning
    a lot of standard assumptions about building
    software

9
Why Everything Youve Been Taught is Wrong
  • AJAX euphoria
  • Web browsers can be made to do anything now!
  • Use desktop / OOP programming style
  • Why its wrong
  • Browsers are being pushed beyond their comfort
    zone
  • JavaScript code is parsed interpreted every
    time ? cost per line of source code

10
Why High-Performance JavaScript is Hard
  • Parsing large amounts of JavaScript is slow
  • Browsers bog down with large DOM
  • Cant rely on browser caching
  • Limited simultaneous network connections
  • Cross-browser is still hard / expensive
  • Poor multi-threading control

11
Why High-Performance JavaScript Matters
  • Everyone is amazed by fast apps
  • It hardly matters what else they do!
  • Everyone hates slow apps
  • It hardly matters what else they do
  • AJAX was supposed to be all about
    responsiveness!!
  • Having tried and almost failed, we now have a
    mantra

12
The High-Performance JS Mantra
  • Be Lazy Nothing is faster than doing nothing
  • Be Responsive Jump when the user says jump
  • Be Pragmatic Dont make things even harder
  • Be Vigilant Only you can prevent slow web apps

13
The High-Performance JS Mantra
  • Be Lazy Nothing is faster than doing nothing
  • Be Responsive
  • Be Pragmatic
  • Be Vigilant

14
How to Be Lazy
Be Lazy Nothing is faster than doing nothing
  • Write less code!
  • Load JS on-demand
  • Draw UI as late as possible

15
Write less code
Be Lazy Nothing is faster than doing nothing
  • Initial parsing of JavaScript is often a major
    bottleneck
  • No JIT, no cached object code, interpreted every
    time
  • Parse time is non-linear in the size of total
    JavaScript?
  • Cant rely on browser caching to excuse large
    code size
  • Yahoo study surprising number of hits with empty
    cache
  • Frequent code releases ? frequently need to
    re-download
  • More code more to download, execute, maintain,
    etc.
  • Ideal for large AJAX apps is lt500K JS uncompressed

16
Total code size of some AJAX apps
17
Write less code
Be Lazy Nothing is faster than doing nothing
  • Minimize the JavaScript code you send down
  • Minify good, obfuscate not much better
  • Strip debug / logging lines (dont just set
    log-level 0)
  • Remove unnecessary OOP boilerplate
  • Get/Set functions dont actually protect member
    vars! etc.
  • Minimize dependency on third-party library code
  • Lots of extra code comes along that you dont
    need
  • Libraries solve more general problems ? use like
    scaffolding

18
Load JavaScript on-demand
Be Lazy Nothing is faster than doing nothing
  • Once youve written less code, load it only
    as-needed
  • Break into classes / modules use require /
    provide (ala dojo)
  • Bundle classes into packages to minimize server
    round-trips
  • Each package should know which dependencies will
    already be loaded
  • Tradeoff of downloading shared code twice vs.
    multiple round trips (e.g. for common widgets)
  • Build packages with error-handler hook for
    development
  • Will re-build from source every time if you dont
    write

19
Load JavaScript on-demand
Be Lazy Nothing is faster than doing nothing
  • Pre-compress packages and serve as .js.gz files
  • Use apache mod_negotiation and mod_deflate
  • Specify MultiViews and serve .js.gz from disk
  • For caching, be sure to vary on user-agent
    (proxies)
  • Use separate sub-domains for JS / CSS / IMG /
    AJAX
  • Otherwise downloading JS blocks other resources
  • Stage loading of important stuff first
  • Dont want little extras blocking the major UI
    from showing up

20
Draw UI as late as possible
Be Lazy Nothing is faster than doing nothing
  • Draw less DOM faster to draw, browser less
    saturated
  • Never pre-draw hidden UI if you can avoid it
  • Cache previously drawn HTML when appropriate
  • But have to know when to invalidate the cache
  • Dont keep hidden UI up-to-date behind the scenes
  • Just re-draw next time you show it (simpler,
    one-time cost)
  • Consider re-drawing vs. partial dynamic UI
    updates
  • Redraw is often faster / easier / less code

21
Never pre-draw hidden UI
22
Never pre-draw hidden UI
23
Never pre-draw hidden UI
24
Never pre-draw hidden UI
25
Never pre-draw hidden UI
26
Never pre-draw hidden UI
27
How to Be Lazy
Be Lazy Nothing is faster than doing nothing
  • Write less code!
  • Load JS on-demand
  • Draw UI as late as possible

28
The High-Performance JS Mantra
  • Be Lazy
  • Be Responsive Jump when the user says jump
  • Be Pragmatic
  • Be Vigilant

29
How to Be Responsive
Be Responsive Jump when the user says jump
  • Minimize initial perceived loading time
  • Yield early and often for responsive UI
  • Cache backend responses with data-manager layer

30
Minimize initial perceived load time
Be Responsive Jump when the user says jump
  • Put CSS at the top of your page and JS at the
    bottom
  • Draw major placeholder UI with loading first
  • Load / draw your app in stages (lazy, on-demand)

31
Load your app in stages
32
Load your app in stages
33
Load your app in stages
34
Load your app in stages
35
Load your app in stages
36
Load your app in stages
37
Load your app in stages
38
Yield early and often
Be Responsive Jump when the user says jump
  • Always want to show a quick response
    acknowledgement
  • TiVo immediate audio / visual feedback, even for
    slow tasks
  • Browser often doesnt update UI until your code
    yields!
  • Solution do minimum work, use setTimeout(0) to
    yield
  • Use closures to chain state together with
    periodic pauses
  • Draw UI progressively, with loading messages as
    needed
  • Demo http//josephsmarr.com/oscon-js/yield.html
  • Use onmousedown instead of onclick (100msec
    faster!)

39
Use closures to yield and maintain state
  • function showMoreInfo(contact_id)
  • var contactObj getContact(contact_id)
  • contactObj.showLoadingMessage() // respond
  • var doTheRest function()
  • contactObj.drawMoreInfo() // use closure
  • setTimeout(doTheRest, 0) // yield

40
Cache backend responses
Be Responsive Jump when the user says jump
  • All data requests should go through data-manager
    code
  • Request as needed and cache results for
    subsequent asks
  • Requesting code always assumes async response
  • Use range caches ? only fill in missing pieces
  • Ideal for partial views into long lists of data
  • Balance local updates vs. re-fetching from APIs
  • Do the easy cases, but beware of too much update
    code
  • Worst case trash cache and re-fetch
    first-time case

41
How to Be Responsive
Be Responsive Jump when the user says jump
  • Minimize initial perceived loading time
  • Yield early and often for responsive UI
  • Cache API responses with data-manager layer

42
The High-Performance JS Mantra
  • Be Lazy
  • Be Responsive
  • Be Pragmatic Dont make things even harder
  • Be Vigilant

43
How to Be Pragmatic
Be Pragmatic Dont make things even harder
  • Play to the browsers strengths
  • Cheat when you can / should
  • Inline initial API calls / HTML for faster load
    time

44
Play to the browsers strengths
Be Pragmatic Dont make things even harder
  • Avoid DOM manipulation use innerHTML and
    array.join()
  • Avoid dynamic CSS-class definitions CSS math
  • Avoid reflow when possible (esp. manually on
    browser resize)
  • Avoid memory allocation (e.g. string-splitting)
  • Do DOM manipulation off-DOM, then re-insert at
    the end

45
Cheat when you can / should
Be Pragmatic Dont make things even harder
  • Use global functions or IDs when reasonable
  • Finding by class / attaching event handlers is
    slow
  • Protect modularity only when needed (e.g.
    widgets)
  • Directly attach onclick, etc. handlers instead of
    using event listeners where appropriate
  • Use fastest find-elems available when you need to
    scan the DOM (dont rely on general-purpose code)

46
A faster way to find elems by class
  • function findElems(parent, nodeType, classStr,
    returnFirstMatch)
  • if(!nodeType) nodeType "" // specify
    nodeType when possible
  • var matches
  • if (!returnFirstMatch) matches
  • var candidateNodes parent.getElementsByTagName
    (nodeType)
  • var node, i 0
  • while(node candidateNodesi)
  • if (node.className.indexOf(classStr) ! -1)
    // could be safer
  • if (returnFirstMatch) return node //
    return fast when possible
  • else matches.push(node)
  • return returnFirstMatch ? null matches

47
Inline initial API calls HTML
Be Pragmatic Dont make things even harder
  • Tempting to load blank page and do everything in
    JavaScript
  • Have to redraw UI dynamically dont want two
    copies of UI code
  • Problem initial load is usually too slow
  • Too many round-trips to the server too long
    before initial UI shows up
  • Solution if you have to do it every time, do it
    statically
  • Save out initial API responses in web page
  • Use data-manager to hide pre-fetching (can change
    your mind later)
  • Download initial HTML in web page

48
How to Be Pragmatic
Be Pragmatic Dont make things even harder
  • Play to the browsers strengths
  • Cheat when you can / should
  • Inline initial API calls / HTML for faster load
    time

49
The High-Performance JS Mantra
  • Be Lazy
  • Be Responsive
  • Be Pragmatic
  • Be Vigilant Only you can prevent slow web apps

50
How to Be Vigilant
Be Vigilant Only you can prevent slow web apps
  • Profile like crazy
  • Consider performance from day one
  • Get your priorities straight

51
Profile like crazy
Be Vigilant Only you can prevent slow web apps
  • Bottlenecks abound and are usually not obvious
  • e.g. CPU parse time vs. download time for large
    JS files!
  • Use firebugs profiler (Joe Hewitt, you rule! ?)
  • Use timestamps diffs and alerts
  • Comment-out blocks of code
  • Measure with a consistent environment
  • Browsers bog down ? always restart first
  • Try multiple runs and average (and dont forget
    the cache)

52
Firebug is your friend
53
alert() is your friend too
  • var start new Date().getTime()
  • bunch of code, including timeouts
  • var elapsed new Date().getTime() start
  • alert(loading took elapsed secs)
  • Use utility functions (store timestamp by id)
  • startTimer(calLoad)
  • alertElapsedTime(calLoad)

54
Consider performance from day one
Be Vigilant Only you can prevent slow web apps
  • Apps get slow when you make them do many / slow
    things!
  • Consider how much code / work is needed for each
    feature
  • Is it making the browser work against the grain?
  • What else is suffering for this feature? Is it
    worth it?
  • Make sure everyone remembers how important speed
    is

55
Get your priorities straight
Be Vigilant Only you can prevent slow web apps
  • Building high-performance apps requires the right
    attitude
  • Must consider and prioritize speed in every
    decision
  • Ask what features can I add within this size /
    speed? vs. how small / fast can I get this set
    of features?
  • I had to learn this the hard way (Plaxo 3.0
    almost didnt ship!)

56
How to Be Vigilant
Be Vigilant Only you can prevent slow web apps
  • Profile like crazy
  • Consider performance from day one
  • Get your priorities straight

57
Conclusion Avoid making the same mistakes we did
  • Make the browser happy and it will make you
    happy
  • Web browsers are more like mobile phones than
    desktops
  • Limited, flimsy, temperamental platform being
    stretched beyond its initial design goals
  • But everyones got one, so its still the best
    place to be
  • Dont push the limits unless you have to
  • Often, small quick-loading pages with AJAX
    interactions is best
  • Sometimes you really do need rich, interactive
    controls

58
Just RememberEverything Youve Been Taught is
Wrong
  • Think about performance early and often
  • Write as little code as you need each line has
    a cost
  • Do what the browser wants (whenever possible)
  • Remember the high-performance JavaScript mantra
  • Be lazy
  • Be responsive
  • Be pragmatic
  • Be vigilant

http//JosephSmarr.com
Write a Comment
User Comments (0)
About PowerShow.com