looking for
​t
he holy grail of

MOBILE WEB PERFORMANCE

Adam Bar

performance

The biggest mistake we made as a company was betting too much on HTML5 instead of native

source: statcounter

looking for
​t
he holy grail of

MOBILE WEB PERFORMANCE

Adam Bar

source: soasta

source: soasta

  • network throughput & latency

performance is...

  • server-side throughput

  • page load & render time, including script execution time

  • animations & interactions smoothness

  • PErceived performance (UX)

  • network throughput & latency

performance is...

  • server-side throughput

  • page load & render time, including script execution time

  • animations & interactions smoothness

  • PErceived performance (UX)

network

load & render

runtime

Case study: before

FP: 7.04 s

FMP: 9.76 s

network throughput
& latency

network

load & render

runtime

http/2

network

load & render

runtime

www.http2demo.io

network

load & render

runtime

Case study: with http/2

Before:

FP: 7.04 s

FMP: 9.76 s

after:

FP: 6.84 s

FMP: 9.53 s

http/2 Server push

index.html

index.html

style.css

script.js

network

load & render

runtime

Preload & prefetch

<link rel="preload" as="font" crossorigin="anonymous" 
    type="font/woff2" href="..." />
<link rel="preload" as="image" 
    type="image/png" href="..." />
<link rel="prefetch" href="next.html" />

network

load & render

runtime

Case study: with preload

before:

FP: 6.84 s

FMP: 9.53 s

after:

 

F(M)P: 8.04 s

dns-prefetch

<link rel="dns-prefetch" href="//example.com" />

preconnect

<link rel="preconnect" href="https://example.com" />

prerender

<link rel="prerender" href="https://example.com" />

network

load & render

runtime

content delivery networks

network

load & render

runtime

Plain old http caching

Cache-Control: public, max-age=31536000
  // for immutable content

Cache-Control: no-cache
  // for mutable content

service worker

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

network

load & render

runtime

Case study: with cache

No cache:

 

F(M)P: 8.04 s

with cache:

 

F(M)P: 2.62 s

Case study: with SW

No cache:

 

F(M)P: 8.04 s

with cache:

 

F(M)P: 2.62 s

with sw:

 

F(M)P: 0.67 s

critical rendering path

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

download

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

rendering

?

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

rendering

css blocks rendering

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

scripting

?

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

scripting

css blocks scripting

!

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

parsing

?

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

parsing

JS download blocks parsing

!

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

parsing

JS download blocks parsing

...unless async

<script src="nasty_ads.js" async></script>

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

parsing

JS execution blocks parsing

network

load & render

runtime

critical rendering path

 index.html

 styles.css

 nasty_ads.js

parsing

JS execution blocks parsing

...unless defer

<script src="nasty_ads.js" defer></script>

network

load & render

runtime

use streamed html parsing

inline above-the-fold css

network

load & render

runtime

defer loading rest of css

website obesity crisis

http://idlewords.com/talks/website_obesity.htm

network

load & render

runtime

bundlephobia.com

network

load & render

runtime

network

load & render

runtime

network

load & render

runtime

https://aerotwist.com/blog/the-cost-of-frameworks/

load

parse

compile

execute

react on iphone 5s:

118 ms

network

load & render

runtime

network

load & render

runtime

https://whatdoesmysitecost.com

  • tree-shaking

  • code splitting

  • critical thinking & common sense

network

load & render

runtime

Case study: unbloated

Before:

CSS: 46 kB

JS: 137 kB

after:

CSS: 11 kB

JS: 78 kB

FP: 5.25 s

FMP: 5.98 s


F(M)P: 8.04 s

26% faster!

image optimization

  • format & compression

  • responsiveness via srcset attribute or <picture> element

<img src="small.jpg" srcset="medium.jpg 1000w, large.jpg 2000w">

network

load & render

runtime

runtime performance

network

load & render

runtime

pixel pipeline

1 s / 60 frames = ~16 ms/frame

60 fps

style

layout

paint

composite

HTML/JS

network

load & render

runtime

https://csstriggers.com

.moving-element {
  will-change: transform;
}

network

load & render

runtime

beware of scroll event

 

 

~16 ms

style

layout

paint

composite

JavaScript

network

load & render

runtime

beware of scroll event

network

load & render

runtime

...and wheel events

...and touch events

document.addEventListener(
   'touchstart', handler, {passive: true});

requestAnimationFrame

function animationStep() {
  // animate
  requestAnimationFrame(animationStep);
}

requestAnimationFrame(animationStep);

requestIdleCallback

function heavyComputation() { /* ... */ }

requestIdleCallback(heavyComputation);

network

load & render

runtime

look for easy wins

prioritize performance

ship less code

look for easy wins

prioritize performance

ship less code

https://slides.com/adambar/mobilewebperf

Adam Bar

@NOtherDev

Made with Slides.com