Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Adaptive Loading - Improving the UX for billions on low-end devices

Addy Osmani
November 20, 2019

Adaptive Loading - Improving the UX for billions on low-end devices

Adaptive Loading is a web performance pattern where sites not just respond based on screen size - they adapt based on actual device hardware.

Any user can have a slow experience. In a world with widely varying device capabilities, a "one-size" fits all experience may not always work. Sites that delight users on high-end devices can be unusable on low-end ones, particularly on median mobile and desktop hardware and in emerging markets. What if we could adapt how we deliver pages to better cater for our user's constraints?

https://addyosmani.com/blog/adaptive-loading/
https://web.dev/adaptive-loading-cds-2019/
Video: https://youtu.be/puUPpVrIRkc

Addy Osmani

November 20, 2019
Tweet

More Decks by Addy Osmani

Other Decks in Technology

Transcript

  1. Addy Osmani Chrome @addyosmani Adaptive Loading Improving the UX for

    billions on low-end devices Nate Schloss Facebook @n8schloss
  2. The Performance Gap On Desktop src: Amazon (bit.ly/bestsellinglaptops - November,

    2019) + Geekbench V5, @addyosmani Highest selling laptops on Amazon (2019) CPU performance using Geekbench 5
  3. Fine-tune Data Transfer Use less bandwidth on slow connections Respect

    Data Saver preferences Reduce memory use on low-cost devices Optimize loading of memory-intensive resources Toggle memory-intensive animations Limit costly JavaScript on low-end devices Avoid loading CPU-heavy components Reduce CPU-intensive code execution Network Memory CPU
  4. const network = navigator.connection.effectiveType; console.log ("Effective connection type is "

    + network); // 3g Network-aware Resource Loading import { useNetworkStatus } from './network'; const { effectiveConnectionType } = useNetworkStatus(); ... switch(effectiveConnectionType) { case '3g': media = <img src='low-res-image.jpg'/>; break; case '4g': media = <video muted controls><source src='video.mp4'></video>; break;
  5. const saveData = navigator.connection.saveData; if (saveData) { // Don’t load

    heavy resources } Data-Saver aware Resource Loading import { useSaveData } from './save-data'; const { saveData } = useSaveData(); ... return ( <div> { saveData ? <img src='...' /> : <video> } </div>
  6. Data Saver Mode For Images Reduction for data-usage from images

    on web. 96% incl disabled video autoplay 80% Twitter’s Data Saver mode presents images as a preview. The web renders a 64x64 blurred image (LQIP style). Users can tap to load large images. Previews load quick on 2G & 3G. Reduction for data-usage from images on iOS + Android 50%
  7. .image { background-image: url("original.webp"); } @media (prefers-reduced-data: reduce) { /*

    Save-Data: On */ .image { background-image: url("compressed.webp"); } } `prefers-reduced-data` bit.ly/csswg-prd Proposal
  8. const memory = navigator.deviceMemory console.log ("Device has at least "

    + memory + "GB of RAM.") // Device has at least 4GB of RAM Memory-aware Resource Loading import { useMemoryStatus } from './memory'; const { deviceMemory } = useMemoryStatus(); ... return ( <div> { deviceMemory < 4 ? <img src='...' /> : <video> } </div>
  9. Page Request Check Device Class & Network Module Server responds

    zoom.js related.js cart.js “Lite” core experience for everyone High-end only features Adaptive Module Serving - The Future? vendor.js magnifier.js modal.js ui_library.js utilities.js /product-page product.js videos.js AR.js
  10. Home Products Product Item Component Image Viewer Zoom Carousel Image

    Viewer Low-end device High-end device Adaptive Code-splitting & Code-loading Core experience
  11. import React, { Suspense } from 'react'; const Sample =

    React.lazy(() => import('./Sample')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <Sample /> </Suspense> </div> ); } React.lazy() and Suspense
  12. Network-aware Code-splitting import React, { Suspense } from 'react'; const

    myComponent = React.lazy(() => { return new Promise(resolve => { navigator.connection ? resolve(navigator.connection.effectiveType) : resolve(null) }).then((effectiveType) => { switch (effectiveType) { case "3g": return import(/* webpackChunkName: "light" */ "./Light.js"); break; case "4g": return import(/* webpackChunkName: "heavy" */ "./Full.js"); break;
  13. Adaptive Serving Fast? Lazy-load more features, like zooming. Slow? Just

    load the core experience eBay are experimenting with adaptive serving using effectiveType. On a fast connection, features like product zooming will load on demand. On slow connections, they won’t.
  14. const cores = window.navigator.hardwareConcurrency console.log ("# logical processor cores are

    " + cores) // 4 CPU Core-aware Resource Loading import { useHardwareConcurrency } from './hardware-concurrency'; const { numberOfLogicalProcessors } = useHardwareConcurrency(); return ( <div> { numberOfLogicalProcessors <= 4 ? <img src='...' /> : <video><source src='...'> } </div>
  15. Home Products Product Fast connection Slow connection Adaptive Data-fetching &

    Pre-fetching GraphQL server Database Database Database 5 results 25 results
  16. Disable video autoplay on slow networks Only prefetch in-viewport links

    on 4G if (!isOKConnection() || isDataSavingMode()) { // don't prefetch visible routes return; } Limit carousel image loads on Data Saver / 3G
  17. Client Server Request client sends current Client Hints Adaptive Delivery

    with Client Hints Subsequent requests Accept-CH: Device-Memory,Save-Data,Viewport-Width Device-Memory: 4 Viewport-Width: 320 Save-Data: 1 <meta http-equiv="Accept-CH" content="Device-Memory, Viewport-Width, Save-Data"> Enable Added Response
  18. User Agent String “Moto G4” “Single-core score: 684” Device Class

    Detection Device Name Detection Service RAM Device Class “Low-end” Geekbench CPU benchmarks Cores CPU score
  19. On mobile we get the device name in the UA,

    so we can use the year class concept. Grouping Hardware On Mobile
  20. “Mozilla/5.0 (Linux; Android 10; SM-G955U) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0

    Chrome/79.0.0.0 Mobile Safari/537.36” “Mozilla/5.0 (Linux; Android 9; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.0.0 Mobile Safari/537.36” Mobile UserAgents tell us what the device is
  21. “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like

    Gecko) Chrome/79.0.0.0 Safari/537.36” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.0.0 Safari/537.36” On desktop things aren’t so obvious...
  22. • UA tells us OS, but not much else •

    What do we have? ◦ Most desktop browsers have: navigator.hardwareConcurrency ◦ Many desktop browsers have: navigator.deviceMemory Grouping Hardware on Desktop
  23. 1) Log hardwareConcurrency and deviceMemory 2) Group by hardwareConcurrency, deviceMemory

    and OS when looking at perf data 3) Figure out buckets based on groupings
  24. Adaptive Loading Serve low-quality images & videos Conditionally load heavier

    JS on fast devices Avoid computationally heavy operations Turn off or throttle Animations Block 3rd-party scripts on slower devices