To push, or not to push?! A journey of resource loading in the - - PowerPoint PPT Presentation

to push or not to push
SMART_READER_LITE
LIVE PREVIEW

To push, or not to push?! A journey of resource loading in the - - PowerPoint PPT Presentation

To push, or not to push?! A journey of resource loading in the browser Fluent Conference, June 2018 Patrick Hamann @patrickhamann Why? HTTP/2 will solve this Everybody @patrickhamann Resource loading in the browser is hard.


slide-1
SLIDE 1

To push, or not to push?!

A journey of resource loading in the browser Fluent Conference, June 2018 Patrick Hamann @patrickhamann
slide-2
SLIDE 2
slide-3
SLIDE 3
slide-4
SLIDE 4

Why?

slide-5
SLIDE 5 @patrickhamann

“HTTP/2 will solve this”

– Everybody

slide-6
SLIDE 6 @patrickhamann

Resource loading in the browser is hard.

slide-7
SLIDE 7

Resource loading is hard:

⏱ Performance is tightly coupled to latency 🤞 Connection cost is high 📉 Congestion control is unavoidable 🙉 Critical resources can be hidden Bandwidth is often under-utilised ⚠ Script execution is expensive 💥

slide-8
SLIDE 8 @patrickhamann

How can we load our resources most efficiently?

slide-9
SLIDE 9
slide-10
SLIDE 10 @patrickhamann

A critical request is one that contains an asset that is essential to the content within the users viewport.


 – Ben Schwarz, Calibre

slide-11
SLIDE 11

What are my critical resources?

✅ Critical CSS for current route ✅ Fonts ✅ Hero images ✅ Initial application route
 ✅ Application bootstrap data

slide-12
SLIDE 12 User navigates First Contentful Paint First Meaningful Paint Time to Interactive Fully loaded
slide-13
SLIDE 13 User navigates First Contentful Paint First Meaningful Paint Time to Interactive Fully loaded
slide-14
SLIDE 14

A good loading strategy:

✅ Prioritises above-the-fold rendering ✅ Prioritises interactivity ✅ Is easy to use ✅ Is measurable

slide-15
SLIDE 15

Preload

slide-16
SLIDE 16 @patrickhamann Request page Network Renderer GET html Build DOM response Build CSSOM First paint GET css response idle idle Render blocking GET font response Text paint Text blocking Render tree

😣

slide-17
SLIDE 17

What are my hidden sub-resources?

✅ Fonts ✅ Application data ✅ Application routes ✅ Async third parties

slide-18
SLIDE 18 @patrickhamann

Provides a declarative fetch primitive that initiates an early fetch and separates fetching from resource execution.

slide-19
SLIDE 19 @patrickhamann 1 <!-- preload stylesheet resource via declarative markup --> 2 <link rel="preload" href="/styles.css" as="style"> 3 4 <!-- or, preload stylesheet resource via JavaScript --> 5 <script> 6 const res = document.createElement("link"); 7 res.rel = "preload"; 8 res.as = "style"; 9 res.href = "lazy-loaded-styles.css"; 10 document.head.appendChild(res); 11 </script> 1 Link: <my-awesome-font.woff>; rel=preload; as=font; crossorigin 2 Link: <application-data.json>; rel=preload; as=fetch; 3 Link: <sub-module.mjs>; rel=modulepreload; Preload with markup: Preload with HTTP header:
slide-20
SLIDE 20

Before

slide-21
SLIDE 21

After

slide-22
SLIDE 22 @patrickhamann

Shopify’s switch to preloading fonts saw a 50% (1.2 second) improvement in time-to- text-paint. This removed their flash-of-invisible text completely.
 
 – Shopify

slide-23
SLIDE 23

Preconnect

slide-24
SLIDE 24

Preconnect No preconnect

index.html main.css app.js font.woff Time index.html main.css app.js font.woff Time
slide-25
SLIDE 25 @patrickhamann

Are indicating resource hints via the HTML response too late?

slide-26
SLIDE 26

Server push

slide-27
SLIDE 27 @patrickhamann Client CDN/Surrogate/Server Origin Time GET /index.html GET /index.html /index.html 2 GET main.css GET /main.css /index.html 2 Server think time

😣

slide-28
SLIDE 28 Jake Archibald – https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/
slide-29
SLIDE 29 @patrickhamann
  • Client
  • Server
Stream Message :method: GET :path: /image-2.jpg Frame :status 200 :version: HTTP/2.0 :vary: Accept-Encoding Frame … response payload Frame Connection Stream A virtual channel within an established connection which carries bidirectional messages. Frame The smallest unit of communication, which carries a specific type of data—e.g., HTTP headers, payload, commands e.t.c. Message A complete sequence of frames that map to a logical HTTP message, such as a request.

Multiplexing

slide-30
SLIDE 30 @patrickhamann Client CDN/Surrogate/Server Origin Time GET /index.html GET /index.html /index.html L i n k : < m a i n . c s s > ; r e l = p r e l
  • a
d PUSH_PROMISE m a i n . c s s /index.html main.css 2 Server think time
slide-31
SLIDE 31 @patrickhamann

So how can I push?

slide-32
SLIDE 32 @patrickhamann 1 Link: <font.woff2>; rel=preload; as=font crossorigin Indicate push via preload Link header. 1 Link: <main.css>; rel=preload; as=style; nopush U s e n
  • p
u s h a t t r i b u t e t
  • d
i s a b l e p u s h s e m a n t i c s a n d
  • n
l y u s e p r e l
  • a
d . 1 Link: <application.js>; rel=preload; as=style; x-http2-push-only F a s t l y u s e s x
  • h
t t p 2
  • p
u s h
  • n
l y a t t r i b u t e t
  • d
i s a b l e p r e l
  • a
d s e m a n t i c s
slide-33
SLIDE 33

Before index.html main.css app.js font.woff

Time
slide-34
SLIDE 34

After index.html main.css app.js font.woff

Time
slide-35
SLIDE 35

Push No Push

index.html main.css app.js font.woff Time index.html main.css app.js font.woff Time

1 RTT saving!

slide-36
SLIDE 36

After index.html main.css app.js font.woff

Time

Idle

😣

slide-37
SLIDE 37 @patrickhamann Client CDN/Surrogate/Server Origin Time GET /index.html GET /index.html /index.html L i n k : < m a i n . c s s > ; r e l = p r e l
  • a
d PUSH_PROMISE m a i n . c s s /index.html main.css 2 Server think time

😣

slide-38
SLIDE 38

Server push benefits:

✅ 1 RTT saving ✅ Useful for long server think time ✅ Useful for long RTT times ⚠ Link header indication is too late

slide-39
SLIDE 39 @patrickhamann

Is indicating push via the HTML response too late?

slide-40
SLIDE 40

Async push

slide-41
SLIDE 41 @patrickhamann Client CDN/Surrogate/Server Origin Time

😏

GET /index.html GET /index.html PUSH_PROMISE m a i n . c s s /index.html main.css Server think time /index.html 2
slide-42
SLIDE 42 @patrickhamann 1 const http2 = require('http2'); 2 3 function handler(request, response) { 4 if (request.url === "/index.html") { 5 const push = response.push('/critical.css'); 6 push.writeHead(200); 7 fs.createReadStream('/critical.css').pipe(push); 8 } 9 10 // Generate index response: 11 // - Fetch data from DB 12 // - Render template 13 // etc ... 14 15 response.end(data); 16 } 17 18 const server = http2.createServer(opts, handler); 19 server.listen(80);
slide-43
SLIDE 43 @patrickhamann

1 sub vcl_recv { 2 if (fastly_info.is_h2 && req.url ~ "^/index.html") { 3 h2.push('/critical.css'); 4 } 5 6 // etc ... 7 8 }

slide-44
SLIDE 44

Async push Push

index.html main.css app.js font.woff Time index.html main.css app.js font.woff Time
slide-45
SLIDE 45

Utilising idle network server think time == win! index.html main.css app.js font.woff

Time

😏

slide-46
SLIDE 46 @patrickhamann

What about the repeat view?

slide-47
SLIDE 47 index.html main.css app.js font.woff Time (from disk cache) (from disk cache)

Repeat view

index.html main.css app.js font.woff Time

First view

slide-48
SLIDE 48 @patrickhamann

The server has no knowledge

  • f client cache state.
slide-49
SLIDE 49

In the wild

slide-50
SLIDE 50 @patrickhamann

Faster image loads times,
 15% reduction in time to first byte


 – Facebook

slide-51
SLIDE 51 HTTP2 server push - Facebook https://atscaleconference.com/videos/http2-server-push-lower-latencies-around-the-world/
slide-52
SLIDE 52 Nikkei.com - Web performance made easy: Addy Osmani, Ewa Gasperowicz https://youtu.be/Mv-l3-tJgGk
slide-53
SLIDE 53 @patrickhamann

Poll?

slide-54
SLIDE 54

So what’s the problem?

slide-55
SLIDE 55 Client CDN/Surrogate/Server Time @patrickhamann GET /index.html PUSH_PROMISE m a i n . c s s main.css RST_STREAM m a i n . c s s
slide-56
SLIDE 56 Client CDN/Surrogate/Server Time @patrickhamann GET /index.html PUSH_PROMISE m a i n . c s s main.css RST_STREAM m a i n . c s s
slide-57
SLIDE 57 @patrickhamann HTTP cache Service Worker Push cache Push cache Memory cache Memory cache Page Page Server S e p a r a t e p u s h c a c h e p e r H T T P / 2 c
  • n
n e c t i
  • n
.
slide-58
SLIDE 58

Push cache semantics

⚠ Connection must be authoritative ⚠ Cache per HTTP/2 connection ⚠ Items can only be claimed once ⚠ It’s the last cache ⚠ It’s not spec’d

slide-59
SLIDE 59 HTTP/2 push is tougher than I thought – Jake Archibald https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/
slide-60
SLIDE 60

HTTP/2 Server Push - Browser inconsistencies

✅ ✅ ⚠ ⚠

slide-61
SLIDE 61 @patrickhamann

0.008% of requests on the Fastly network are push initiated.

slide-62
SLIDE 62

When should I push?

✅ You have long RTTs or server processing ✅ You can use async push ✅ You have a client-rendered app shell (PRPL) ✅ You control the client cache (SW, native, Electron etc)

slide-63
SLIDE 63 @patrickhamann

Is the 1 RTT saving worth the complexity?

slide-64
SLIDE 64 @patrickhamann

Are there other solutions?

slide-65
SLIDE 65

The future

slide-66
SLIDE 66 @patrickhamann

Can we fix the problems with push?

slide-67
SLIDE 67

Cache digests

slide-68
SLIDE 68 Client CDN/Surrogate/Server Time @patrickhamann GET /index.html CACHE_DIGEST PUSH_PROMISE m a i n . c s s main.css /index.html
slide-69
SLIDE 69 index.html main.css app.js font.woff Time (from disk cache) (from disk cache) (from disk cache)

Repeat view First view

index.html main.css app.js font.woff Time
slide-70
SLIDE 70 index.html main.css app.js font.woff Time (from disk cache) (from disk cache) (from disk cache)

Repeat view First view

index.html main.css app.js font.woff Time

😏

slide-71
SLIDE 71 IETF Draft Cache Digests for HTTP/2 - K. Oku, Y. Weiss https://tools.ietf.org/html/draft-ietf-httpbis-cache-digest-04
slide-72
SLIDE 72 @patrickhamann

This still seems too complicated…

slide-73
SLIDE 73

103 Early hints

slide-74
SLIDE 74 @patrickhamann

The 103 (Early Hints) informational status code indicates to the client that the server is likely to send a final response with the header fields included in the informational response.

slide-75
SLIDE 75 @patrickhamann Client CDN/Surrogate/Server Origin Time GET /index.html GET /index.html /index.html Server think time L i n k : < m a i n . c s s > ; r e l = p r e l
  • a
d 1 3 GET /main.css /index.html 2 main.css
slide-76
SLIDE 76 @patrickhamann

1 HTTP/1.1 103 Early Hints 2 Link: </style.css>; rel=preload; as=style 3 Link: </main.js>; rel=preload; as=script 4 Link: </application-data.json>; rel=preload; as=fetch 5 6 HTTP/1.1 200 OK 7 Date: Thu, 14 June 2018 16:10:00 PDT 8 Content-length: 1234 9 Content-type: text/html; charset=utf-8 10 Link: </main.css>; rel=preload; as=style 11 Link: </newstyle.css>; rel=preload; as=style 12 Link: </main.js>; rel=preload; as=script

slide-77
SLIDE 77 IETF RFC8297 Early Hints - K. Oku https://tools.ietf.org/html/rfc8297
slide-78
SLIDE 78

103 Early hints:

✅ Same benefits as push ✅ Much simpler ✅ Leverages the browser caches ✅ Allows client to initiate fetches ⚠ No 1 RTT saving

slide-79
SLIDE 79

Priority hints

slide-80
SLIDE 80 Web performance made easy: Addy Osmani, Ewa Gasperowicz https://youtu.be/Mv-l3-tJgGk
slide-81
SLIDE 81 Priority Hints draft - https://github.com/WICG/priority-hints
slide-82
SLIDE 82

Closing

slide-83
SLIDE 83 @patrickhamann

HTTP/2 doesn’t solve everything.

slide-84
SLIDE 84 @patrickhamann

Resource loading is hard.

slide-85
SLIDE 85 @patrickhamann

Performance is for humans. Optimise for user experiences.

slide-86
SLIDE 86 @patrickhamann

The future is bright!

slide-87
SLIDE 87

Resource loading checklist:

✅ Identify your critical resources ✅ Preload hidden sub-resources ✅ Preconnect critical third-parties ❌ Avoid pushing with preload ⚠ Use async push with care 🚁 Decorate HTML with priority hints 🚁 Use Early Hints when available

slide-88
SLIDE 88

Thanks!

Patrick Hamann speakerdeck.com/patrickhamann
 patrick@fastly.com @patrickhamann