VanJS: Performance and the mobile web

VanJS: Performance and the mobile web

With mid-range smartphones now rocking 2-core processors and LTE wireless speeds of over 20 Mbps, it seems like we're out of the woods on mobile performance. Then why doesn't the mobile web feel faster? In this talk I'll review the numbers showing why performance still matters and discuss some of what you can do about it.

429a32ee70f8f86fd12b722a6050f0c4?s=128

Peter McLachlan

February 12, 2013
Tweet

Transcript

  1. mobify.com @mobify hello@mobify.com Performance and the mobile web: why it

    still matters & what you can do about it (we’re hiring!) 1
  2. mobify.com @mobify hello@mobify.com About me 2 Peter McLachlan chief architect

    & co-founder @ Mobify Research & Development
  3. mobify.com @mobify hello@mobify.com Mobify 3

  4. mobify.com @mobify hello@mobify.com Trusted by Leading Companies 4

  5. mobify.com @mobify hello@mobify.com Some questions for you: 5 Interactive --

    ask some questions, solicit some responses.
  6. mobify.com @mobify hello@mobify.com Audience question What kinds of optimizations do

    you make for web performance? 6
  7. mobify.com @mobify hello@mobify.com Audience question What is different about mobile?

    7 •Hope for the following answers: •Battery •CPU •screen DPI •latency
  8. mobify.com @mobify hello@mobify.com Trends in the mobile web 8

  9. mobify.com @mobify hello@mobify.com Latest Trends - Metrics 9

  10. mobify.com @mobify hello@mobify.com Latest Trends - International Mobile Growth Image

    Credit: Brad Frost 10
  11. mobify.com @mobify hello@mobify.com What about mobile design? 11

  12. mobify.com @mobify hello@mobify.com Responsive design Ethan Marcotte “Fluid grids, flexible

    images, and media queries are the three technical ingredients for responsive web design” RESPONSIVE WEB DESIGN 12 We won’t talk about Responsive web design in a couple of years. Not because it’s gone away but because it will just be “web design” and people won’t do it any other way!
  13. mobify.com @mobify hello@mobify.com Adaptive Web Image Credit: Brad Frost 13

  14. mobify.com @mobify hello@mobify.com Adaptive Web Image Credit: Brad Frost 14

  15. mobify.com @mobify hello@mobify.com What makes mobile websites slow 15

  16. mobify.com @mobify hello@mobify.com Blocking resources 16 External CSS CSS includes

    via @import (Most) Javascript
  17. mobify.com @mobify hello@mobify.com Non-blocking resources 17 Most images (sorta) Async

    or deferred scripts
  18. mobify.com @mobify hello@mobify.com Bandwidth 18 Not out of the woods

    yet ... most of us are between the first pillar and the second pillar. Actual speeds tend to be a lot slower than theoretical maximums.
  19. mobify.com @mobify hello@mobify.com Latency Source: Ilya Grigorik (Google) 19

  20. mobify.com @mobify hello@mobify.com Latency 20

  21. mobify.com @mobify hello@mobify.com What does this mean? 0%# 10%# 20%#

    30%# 40%# 50%# 60%# 70%# 80%# 90%# 100%# 100ms# 1s# 2s# 3s# 4s# 5s# 6s# 7s# 8s# 9s# 10s# eCommerce'sales'lost'due'to'load'.me' Source: Amazon web team (1% sales lost per 100ms) 21
  22. mobify.com @mobify hello@mobify.com No problem, we’ll make c faster Image

    credit: XKCD - “relativistic baseball” 22
  23. mobify.com @mobify hello@mobify.com Parsing: HTML 23 Unfortunately Responsive HTML is

    usually even more complicated
  24. mobify.com @mobify hello@mobify.com Image Credit: Guy Podjarny 24 http://www.guypo.com/mobile/javascript-pre-execution-for-mobile-taking-scripts-out-of-the-loop/

  25. mobify.com @mobify hello@mobify.com Amount of JS 25 Phone slow JS

    execution. iPhone 4 -> iPhone 4s, 2x cpu, 15% better JS!
  26. mobify.com @mobify hello@mobify.com CSS Complexity html body.s_blog section#page div.entry-content span.entry-body,

    html body.s_blog body.indexB section#page div.entry-content .hentry div.text, html body.indexB body.s_blog section#page div.entry-content .hentry div.text, html body.s_blog body.indexB section#page .hentry div.entry-content div.text, html body.indexB body.s_blog section#page .hentry div.entry-content div.text, html body.s_blog body.indexB section#page div.entry-content .dragrace-holder section.feature.dragrace div.text, html body.indexB body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.text, html body.s_blog body.indexB section#page .dragrace-holder section.feature.dragrace div.entry-content div.text, html body.indexB body.s_blog section#page .dragrace-holder section.feature.dragrace div.entry-content div.text, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content .hentry div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content .hentry div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content .hentry div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content .hentry div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page .hentry div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page .hentry div.main-column .item-inner #slideshow- description-outer div.entry-content div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .hentry div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content div.main-column .item- inner #slideshow-description-outer .hentry div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.main-column .item-inner #slideshow-description- outer .hentry div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry-content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content div.main-column .item-inner #slideshow-description- outer .hentry div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow-description- outer .hentry div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry- content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.main-column .item-inner #slideshow-description-outer .hentry div.entry-content div.item- footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry- content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow- description-outer div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.main- column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry- content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page .dragrace-holder section.feature.dragrace div.main-column .item-inner #slideshow-description-outer div.entry- content div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.s_blog body.indexB body.list.listC .container section#page div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.entry-content div.item-footer, html body.indexB body.list.listC .container body.s_blog section#page div.main-column .item- inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.entry- content div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.entry-content div.main-column .item-inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.entry-content div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.item-footer, html body.s_blog body.list.listC .container body.indexB section#page div.main-column .item-inner #slideshow- description-outer .dragrace-holder section.feature.dragrace div.entry-content div.item-footer, html body.list.listC .container body.indexB body.s_blog section#page div.main-column .item- inner #slideshow-description-outer .dragrace-holder section.feature.dragrace div.entry- content div.item-footer { font-size: 13px; display: block; margin-top: 10px; } 26 CSS Selector of shame Please never do this.
  27. mobify.com @mobify hello@mobify.com Layout reflow + Painting • Repaints --

    also maybe raid some stuff from Ilya’s presentation 27
  28. mobify.com @mobify hello@mobify.com What causes these? • clientHeight • clientLeft

    • clientTop • clientWidth • focus • getBoundingClientRect • getClientRects • innerText • offsetHeight • offsetLeft • offsetParent • offsetTop • offsetWidth • outerText • scrollByLines • scrollByPages • scrollHeight • scrollIntoView • scrollIntoViewIfNeeded • scrollLeft • scrollTop • scrollWidth • MouseEvent • layerX • layerY • offsetX • offsetY • Window • getComputedStyle • scrollBy • scrollTo • scrollX • scrollY • Frame • Document & Image • height • width Any DOM modification or: 28
  29. mobify.com @mobify hello@mobify.com Making sites faster: strategy 29

  30. mobify.com @mobify hello@mobify.com Moving down is hard Image Credit: Brad

    Frost 30 This is the way we’ve usually done things. Time to turn it around.
  31. mobify.com @mobify hello@mobify.com The Web of the Future Mobile First:

    Smartphone *and* Tablet 31
  32. mobify.com @mobify hello@mobify.com Mobile first! Image Credit: Brad Frost 32

  33. mobify.com @mobify hello@mobify.com Performance anti- patterns 33

  34. mobify.com @mobify hello@mobify.com Anti-pattern: domain sharding 34 Domain sharding is

    now an anti-pattern. At best it provides neutral results and adds complexity. Complexity is bad. In the future it will probably be a very significant anti-pattern.
  35. mobify.com @mobify hello@mobify.com Anti-pattern: blocking JavaScript at the top of

    the document 35
  36. mobify.com @mobify hello@mobify.com Anti-pattern: Large library dependencies 36

  37. mobify.com @mobify hello@mobify.com Anti-pattern: Naive lazy loading Wait, isn’t being

    lazy good? 37 Wait, isn’t lazy-loading good? Sorta. We’re not taking advantage of browser optimizations!
  38. mobify.com @mobify hello@mobify.com Performance patterns 38

  39. mobify.com @mobify hello@mobify.com Remove unneeded resources • The best optimization

    there is! • Difficult to do, ex post facto • Developer time is precious • Greedy browsers don’t help us out here 39 The best optimization there is! Only load things when we have to! * This sounds pretty easy, but it’s tricky in practice developer time is precious, there’s always another bug to squash usual approach is to throw everything in and hope to have time to wean it down later. This seldom happens. async vs defer
  40. mobify.com @mobify hello@mobify.com Compress assets 40 Again -- seems easy.

    So why don’t more sites do it? * It’s a pain. Easy to do once, difficult to maintain * Even if you write scripts that do it for you, changes can break those deployment scripts * Even sites maintained by large, capable web teams seem not to get this right. Need proof? I’m not going to shame anyone in public, just go visit some top retailer site with developer tools running.
  41. mobify.com @mobify hello@mobify.com Pre-fetching 41 * Nobody has done a

    really great job of this * DNS pre-fetching * Page pre-fetching * Image / JS pre-fetching + localStorage
  42. mobify.com @mobify hello@mobify.com Pre-fetching Homepage Signup Studio Services DNS HTML

    JS CSS Images 42
  43. mobify.com @mobify hello@mobify.com Intelligent radio warmup 43 DCH = Dedicated

    channel FACH = Forward access cannel may be able to transmit small data packets on the random access channel (RACH)
  44. mobify.com @mobify hello@mobify.com Making use of localStorage and “smart” caching:

    localStorage performance 44 Instantiating a 20kb javascript from localStorage
  45. mobify.com @mobify hello@mobify.com Making use of localStorage and “smart” caching:

    native cache performance 45
  46. mobify.com @mobify hello@mobify.com Generic optimizations • CDN • Limit number

    of hosts • Set good caching headers • Far future expires • Cookieless domains 46 * Why limit number of hosts: Tie back to 3-way handshake & domain sharding example * Why cookieless domains make a difference
  47. mobify.com @mobify hello@mobify.com Some resources for performance • https://developers.google.com/speed/ •

    http://www.igvita.com/ (Gregorik Ilya, Google Performance team) • http://stevesouders.com/ (Author of "High Performance Websites, O'reilly & Associates" ) (author of YSlow) • Recommendations? 47
  48. mobify.com @mobify hello@mobify.com Final thoughts 48

  49. mobify.com @mobify hello@mobify.com Performance - we could spend weeks on

    this • There are no shortcuts. To really get into mobile performance you need an engineer who understands: • HTTP/1.1 • pipelining • cacheing rules • TCP/IP • 3-way handshake • congestion control • packet-loss impacts • Web servers • c10k problem & solutions • cacheing • concurrency models • Content Delivery Networks • DNS • latency • cacheing • IP Anycast • DNS • Georouting • Asynchronous network communications • 3G+4G radio behavior ... • Browser concurrency models • what is threaded what is not • synchronous & asynchronous operations • Browser rendering processes • what forces a repaint? • Modern web design • workflow • content • marketing requirements 49
  50. mobify.com @mobify hello@mobify.com 50

  51. mobify.com @mobify hello@mobify.com Thank you! (are you a unicorn? we

    are hiring!) 51