Frontend Performance: Beginner to Expert to Insanity

Frontend Performance: Beginner to Expert to Insanity

There’s no such thing as fast enough. You can always make your website faster. This talk will show you how. The very first requirement of a great user experience is actually getting the bytes of that experience to the user before they they get tired and leave.

In this talk we’ll start with the basics and get progressively insane. We’ll go over several frontend performance best practices, a few anti-patterns, the reasoning behind the rules, and how they’ve changed over the years. How should you tune TCP? Should you combine your JavaScript or split it into multiple files? Should you use a Cookieless domain for CSS or not? How does HTTP/2 affect performance? How do you use Wireshark and browser tools to debug performance issues? We’ll answer most of these questions during this talk.


Philip Tellis

May 31, 2016


  1. FrontEnd Performance Beginner to Expert to Insanity

  2. Philip Tellis @bluesmoon

  3. None
  4. Get the most benefit with the least effort

  5. 0 Start with a really slow site

  6. 0.1 Start Measuring

  7. Or use RUM for real user data (boomerang/mPulse)

  8. • Pre-gzip static assets (gzip_static in nginx) • eg: foo.js.gz

    is served if Accept-Encoding: gzip is included • For dynamic content, use chunked transfers with gzipped chunks • You can do this by flushing buffers on the server 0.2 enable gzip
  9. • Understand newer compression formats like ZopFli, Brotli, and WebP.

    • But also understand the trade-off between better compression and complexity of image decoding on mobile devices 0.2 enable gzip… and compression
  10. In Switzerland, you can get gluten free compression! 737558689297534976

  11. 0.3 Cache Cache-control: public, max-age=31415926 Do NOT set LastModified or

    ETags headers to avoid conditional requests
  12. 0 Congratulations You’ve just been promoted!

  13. 1 What the Experts do

  14. 1.1 CDN • Serve your root domain through a CDN

    • Put CSS on the root domain • Chrome opens two TCP connections to the primary host, the second one is "just in case"
  15. 1.1 Google Chrome will open two TCP connections to the

    primary host, one for the page, and the second "just in case"
  16. 1.2 Split JavaScript • Critical: in the HEAD • Enhancements:

    loaded async • Flush buffers after the HEAD • Approximately 14.4Kb gzipped per file • for HTTP/2, these would have different priorities
  17. 1.3 Parallelize downloads… or maybe don’t • You can have

    more bandwidth, but you cannot have lower latency • For HTTP/1.1, mitigate latency effects by parallelizing across multiple TCP sockets • But with HTTP/2, this rule is turned on its head since multiplexing and pipelining is built in
  18. 1.4 Flush Early and Often • avoid TCP Slow Start,

    • speed up CSS • Help the browser’s lookahead parser Getting bytes to the client ASAP will:
  19. TCP Handshake & Congestion Control

  20. 1.5 Increase initcwnd Initial Congestion Window: Number of packets to

    send before waiting for an ACK
  21. 1.5 Increase initcwnd @mobtec on Twitter

  22. 1.5b Also… net.ipv4.tcp_slow_start_after_idle=0

  23. 1.6 PageSpeed mod_pagespeed and ngx_pagespeed

  24. 1.7 Don’t just FastClick • FastClick fires a Click onTouchEnd

    • It might be better to initiate a TCP connect onTouchStart and fetch content normally onClick • Use <link rel=“preconnect”>
  25. 1.8 Use UserTiming to measure your code • The UserTiming

    API allows you to set performance timeline marks within your code • performance.mark("name") • performance.measure("name",
 "start_mark", "end_mark")
  26. 1.9 Avoid Pre-flighted XHR • Make sure any JS Library

    you use doesn’t automatically add an X-Requested-With header
  27. Relax

  28. 2 Things are gonna get insane!

  29. Sort in ascending order of signal latency • Electrons through

    copper • Light through fibre • Pulsars • Station Wagons • Smoke Signals
  30. Sort in ascending order of signal latency 1.Pulsars (light through

    vacuum) 2.Smoke Signals (light through air) 3.Electrons through copper / Light through fibre 4.Station Wagons (possibly highest bandwidth)
  31. 2.0 Bandwidth is different around the world

  32. 2.0 As are people

  33. 2.0 Study real user data Look for potential places to

    parallelize, predict and cache
  34. 2.1 Use RUM to determine optimum POP location • Use

    RUM to measure latency from user to multiple POPs • Pick POP based on lowest latency • Adapt to changes in network topology
  35. 2.1 Use RUM to determine best CDN • Use RUM

    to measure latency from user to multiple CDN providers • Dynamically pick CDN based on what works best
  36. 2.2 pre-browsing <link rel="prerender" href="url"> <link rel="preload" href=“url" as="type"> <link

    rel="dns-prefetch" href=“url"> <link rel="preconnect" href="url">
  37. 2.2 <link rel=“dns-prefetch”> • Does a DNS lookup for hostname

    mentioned in URL • This could help reduce latency when the request shows up — for first page views at least • Your DNS TTL needs to be long enough to survive past a page load
  38. 2.2 <link rel=“preload”> • Tells the parser that this resource

    will be required later on • Browser can start downloading in the background if it has nothing better to do with its resources • no-cache header only applies to subsequent pages
  39. 2.2 <link rel=“preconnect”> • Tells the browser to open a

    TCP connection to this host, and hold on to it • Any CORS restrictions will apply to this connection
  40. 2.2 <link rel=“prerender”> • Tells the parser that this page

    is likely to be requested by the user • Browser downloads page, and all its resources, renders it, executes JavaScript and fires the onload event. • It’s like opening the page in a hidden Tab
  41. 2.2 <link rel=“prerender”> • When user follows the URL, the

    page just shows up (< 5ms latency) • This is actually faster than switching tabs in the browser • The onVisibilityChange event fires and visibilityState changes from “prerender” to “visible” or “hidden”
  42. 2.2 <link rel=“prerender”> — Caveats • The page needs to

    be requested using GET • The page should not require Authentication (401 response) • Prerender will be aborted if cookies, or localStorage change, or if the prerendered page has non-idempotent components
  43. 2.2 onVisibilityChange And while you’re at it, don’t do expensive

    work if the page is hidden Using_the_Page_Visibility_API
  44. 2.3 Post-load Fetch optional assets after onload

  45. 2.4 Detect broken accept-encoding Many Windows anti-viruses and firewalls disable

    gzip by munging the Accept-Encoding header
  46. 2.5 HTTP/2 • Only one TCP connection per host •

    Do NOT use domain sharding • Do NOT use sprites • Do use Stream Multiplexing with Priorities • Do use Server Push
  47. — Tim Kadlec “4:2:0 subsampling of JPEGs gets a 62.5%

    memory savings” 2.6 Use 4:2:0 Chroma Subsampling Chroma Subsampling takes advantage of the fact that the human visual system is less sensitive to changes in colour than luminance
  48. 2.7 Resize Images for target Device Dimensions Resizing Images for

    specific screen sizes could be the difference between 1.5s and 30ms
  49. 2.8 Decode large images in a Worker Thread fetch(imageURL) //

    Get the image as a blob. .then(response => response.blob()) // Decode the image. .then(blobData => createImageBitmap(blobData)) // Send it to the main thread .then(imageBitmap => { self.postMessage({ imageBitmap }, [imageBitmap]); }, err => { self.postMessage({ err }); });
  50. 2.9 Don’t force layout operations • DOM manipulations followed by

    a read of invalidated properties forces a layout • This has a huge CPU impact • Read before write • Batch update • Move operations into the HEAD Amiya Gupta @ Velocity 2015
  51. 2.10 Understand 3PoFs Use to test for 3rd party

    single points of failure
  52. 2.10 3PoFs Request Map by Simon Hearne

  53. 2.11 Understand your SpeedIndex

  54. 2.12 What does your site cost?

  55. 2.13 Prioritize optimizations based on user impact Conversion Impact Score

    in mPulse DSWB
  56. 2.14 Become a WebPageTest power user • Check out the

    comparison view • Collect packet captures • Use Wireshark • Test out different network types
  57. References • WebPageTest — • Boomerang — •

    SOASTA mPulse — • Netflix gzip study — • Nginx gzip_static — • ImageOptim — • uncss — • grunt-uncss — • Caching — • Same domain CSS — • initcwnd — • Linux TCP Tuning — • Prerender — • DNS prefetching — • Preloading CSS — • FE SPoF — • Page Visibility API — • HTTP/2 — • More Bandwidth is not a Magic Bullet — • The UserTiming API — • The 3.5s dash for attention — • POPs & RUM — • Optimizing Images for Mobile — • Load Images in a Worker Thread — • Optimizing the MSN Homepage — Amiya Gupta @ Velocity 2015 • Simon Hearne’s Webperf Tools — and • What does my site cost — • Reducing JPG File size —
  58. Thank You

  59. Philip Tellis @bluesmoon

  60. Image Credits • Apple Pie • Puppies 7 weeks • Zöpfli