Web performance*
Everything You Always Wanted to Know About
Maurizio Lupo @sithmel
(*But Were Afraid to Ask)
100ms increase in latency = 1% reduction in sales
Amazon
why is it important?
User traffic took months to recover after we deliberately slowed page load times for certain users
why is it important?
For every 1 second improvement in page load time, we saw a 2% conversion increase.
Walmart
why is it important?
why is it important?
SEO: Faster sites get better ranking
why is it important?
Within 0.1 second : feels instant
Within 1 second: fit in the flow of thoughts
Within 10 seconds: keeping the user attention
"Usability engineering" Jacob Nielsen 1993
what to measure
Time to first byte
Time to establish a connection
+
backend time
what to measure
Visual complete / speedindex

what to measure
Visual complete / speedindex

what to measure
App interactive

how to measure it
Syntetic
www.webpagetest.org
Speedcurve
how to measure it
RUM
Browser API: window.performance
Real users monitoring
how to measure it
Important:
Network congestion skews metrics!
Syntethic: take the sample at the same time every day
RUM: watch long period trends
Understanding browser networking: bandwidth
Radius of the pipe
Not an official definition

Understanding browser networking: latency

Length of wires * speed of light + routers * time to route
Not an official definition
Understanding browser networking: latency
3G: 100ms latency
DSL: 5ms latency
Last mile latency:
Geographical latency
San Francisco to NYC carries a minimum 40ms RTT
Understanding browser networking: latency
Improving latency using a CDN

Understanding browser networking: TCP
TCP provides reliable, ordered, and error-checked delivery of a stream of octets between applications running on hosts communicating by an IP network
Understanding browser networking: TCP

If latency is 100ms, opening a connection costs 300ms!
Opening a connection:
Understanding browser networking: TCP

If we sum dns fetch, TCP handshake, tsl negotiation (on a 100ms latency network) it takes 1 second!!!
Understanding browser networking: TCP
Reliable is great but:
Acknowledge reception
Head of line blocking
Congestion control
Understanding browser networking: TCP
Congestion control: slow start

Understanding browser networking: TCP
Congestion control: slow start

Understanding browser networking: TCP
Default opening window size is of 10 packets (almost everywhere)
TCP packet is commonly 1500bytes (MTU)
First 15000 (14KB) are received in a single gulp
Understanding browser networking: TCP
It sucks for short bursty exchanges, especially when latency is big (mobile network for example)
Understanding browser networking: HTTP
Every resource requires a short bursty connections :-(
Understanding browser networking: HTTP
HTTP 1.1 Keepalive: the browser can reuse the same connection :-|
but HTTP head of line blocking
Understanding browser networking: HTTP
Let's open more than one connection for each domain! (usually 8)
:-( Every connection pays the price (slow start)
:-) Parallel download
Understanding browser networking: HTTP
HTTP2 multiplexing
Single connection
Uses binary frames for parallel transmission
HTTP3: http2 over UDP (quic)
What's next?


Understanding browser networking: HTTP
HTTP Features*
*only the ones impacting performances
Understanding browser networking: Caching
cache-control
Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
Cache-control: immutable
Cache-control: stale-while-revalidate=<seconds>
Cache-control: stale-if-error=<seconds>
Understanding browser networking: Caching
cache-control
Good practice: cache assets forever and change name when you need a new version
Understanding browser networking: Caching
conditional GET
1 - The server send the Etag header as key of a resource (not the only method)
2 - The browser asks for the same resource sending the Etag received previously
3 - If the resource didn't change the server respond with a 304: Not modified
HTTP/1.1 304 Not Modified
Date: Sat, 09 Feb 2013 16:09:50 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Sat, 02 Feb 2013 12:02:47 GMT
ETag: "c0947-b1-4d0258df1f625"
Understanding browser networking: Caching
Main page is never cached
You can change default behaviour using
Service workers
Understanding browser networking: Compression
HTTP1.1 can optionally compress the data (gzip for example)

Understanding browser networking: Redirects
Very useful but may hurt performance
HTTP/1.1 301 Moved Permanently
Location: http://www.example.org/
Content-Type: text/html
Content-Length: 174
Understanding browser networking: Chunked encoding
In HTTP1.0 resources uses content-length header
You have to wait to reach that length before reading and parsing the resource
From HTTP1.1 you can use transfer-encoding: chunked
Resources can be parsed without waiting to be fully loaded
Very important for HTML and images!!!!
Domain sharding:
Increase number of parallel transmissions
Transmit cookies only from and to a single domain
HTTP2: They are antipatterns!!!!
HTTP2 multiplexing allows parallel transmissions
HPACK header compression avoid sending cookies more than once
HTTP1:
Mythbusting
Inlining:
HTTP2 or 3: use server push
HTTP1: faster because no extra request (no caching)
Mythbusting
Resource bundling:
HTTP2: still important but smaller bundles (more granular caching)
HTTP1: faster and more efficient
Mythbusting
To be continued ....
Parsing and rendering: HTML
HTML can be parsed (and rendered) progressively!*
*HTTP chunked transfer encoding
Parsing and rendering: HTML
Phase 0: preparsing
Super fast scan of the document searching for resources to download
Parsing and rendering: HTML
Phase 1: parsing
The browser builds the DOM. But it stops on blocking resources.
The CSS should be parsed and the CSSOM built before proceding
JS should be executed before proceding
Parsing and rendering: HTML
Phase 2: rendering
The browser paints on the screen. An update of the CSSOM may trigger a repaint. The content too, but it is rare.
Parsing and rendering: HTML
but also of "client hints":
<link rel="dns-prefetch" href="//example.com">
<link rel="preconnect" href="http://css-tricks.com">
<link rel="preload" href="image.png">
Preparser initiate the download of:
<script src="script.js"></script>
<link rel="stylesheet" href="main.css"/>
<img src="image.jpg"/>
Parsing and rendering: CSS
It blocks the parsing and it can't be parsed progressively.
It can be loaded asynchronously using javascript (but it has to be done cleverly to be picked up by the preparser)
<link
rel="preload"
href="path/to/mystylesheet.css"
as="style"
onload="this.rel='stylesheet'">
Parsing and rendering: CSS
Any resource referenced by the CSS is downloaded only when the rule matches
Example: img tag vs background-image CSS rule
img is always downloaded!
Parsing and rendering: CSS
Minified css is faster to download and parse
Browsers allow link and style tags in the body. It should only block the html underneath
It is also a good idea bundling many css together
but
Parsing and rendering: JS
It blocks the parsing (unless asynchronous) and it can't be parsed progressively.
Parsing and rendering: JS
Loading scripts with javascript:
It can be an antipattern during page load (no preparser involved)
<script>
var script = document.createElement('script');
script.src = "//somehost.com/awesome-widget.js";
document.getElementsByTagName('head')[0].appendChild(script);
</script>
Parsing and rendering: JS
Using defer or async

async: execute as soon as it is ready
defer: execute when html parse is over (it retains the original ordering, but not for inline scripts)
The image is misleading. Download is initiated by the preparser
Parsing and rendering: JS
type="module"
works the same as defer
It enables ESM in the browser (import)
imported modules are bad news for performance, unless you use something like this:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
<link rel="modulepreload" href="./utils.mjs">
Parsing and rendering: JS
JS can be minified and bundled
Big bundles takes longer to download/parse/execute
Different scripts depending from each others require to be executed in order (no async attribute)
Parsing and rendering: images
They never block rendering but:
Trigger a repaint if width and height are not specified
Parsing and rendering: images
Progressive JPEG improve speed perception

Parsing and rendering: fonts
They don't block but text is not rendered if font missing
Flash of Invisible Text
Parsing and rendering: fonts
You can wait to have the font and then apply the font
Flash of Unstyled Text
Parsing and rendering: fonts
The default pattern to download the font is terribly inefficient
html -> load css -> load font
better (also avoids foit/fout)
html -> load css (font inline)
html (inline the font)
This works but defeat caching
HTTP2 server push can help
CSS font-display
@font-face {
font-family: "Open Sans Regular";
font-weight: 400;
font-style: normal;
src: url("fonts/OpenSans-Regular-BasicLatin.woff2") format("woff2");
font-display: swap;
}
Webkit and Mozilla only (no IE or old edge)
Parsing and rendering: fonts
Note: woff fonts are binary and are subjected to same domain policy
No worries you can use CORS
This is going to cost you an extra round trip!
Mythbusting
One less image
busted
Mythbusting
Client side rendering is good enough
partially busted (not on load)
Mythbusting
Minification is useful
True: even if content is gzipped verbose js and css is longer to decompress and parse
Thanks for listening!
Questions?
Web performance
By Maurizio Lupo
Web performance
What you always wanted to know about
- 542