Konrad Kowalski (rootsher)Principal Platform & Reliability Architect010011111011000000100010100011010111100000100100

HTTP/1.1: Where Waterfalls and Bundling Came From

date
category
Networking
also in
Frontend
reading
1 min / 251 words

Frontend practices such as:

text
bundle everything
sprite sheets
inline small assets
domain sharding

did not appear by accident.

A large part of them was an answer to the cost of many requests in HTTP/1.1.

One connection, sequential responses

A simplified model:

text
connection A:
request 1 -> response 1
request 2 -> response 2

If response 1 is slow, the next request on that connection has to wait.

HTTP/1.1 had pipelining, but deployment problems and head-of-line behavior meant that browsers in practice relied mostly on several parallel connections.

So the model of a page looked roughly like:

text
conn 1 ─ CSS ───── image
conn 2 ─ JS ─ font
conn 3 ─ image ─ image
...

The number of parallel lanes was limited.

Request overhead mattered

Every request carried textual headers:

http
GET /assets/icon.svg HTTP/1.1
Host: example.com
Cookie: ...
Accept: ...

With hundreds of small resources the overhead was noticeable.

Hence bundling:

text
100 JS files
      |
      v
bundle.js

We gained fewer requests at the cost of a bigger file and worse cache granularity.

Domain sharding

If the browser limited parallel connections per host, resources could be split:

text
static1.example.com
static2.example.com

to get more parallel connections.

But we paid with:

text
more DNS
more TCP
more TLS

It was a hack that followed from the limits of the transport layer.

Frontend architecture adapted to the protocol

That is an important conclusion.

Build tooling optimizations are not independent of the network.

If the transport rewards:

text
few large files

the bundler will try to reduce the number of requests.

If the transport handles many parallel streams well, the optimum can move towards:

text
more granular resources
better caching
selective loading

Of course the cost of a request never drops to zero.

But its character changes.

The biggest change in HTTP/2

HTTP/2 did not change this:

http
GET /app.js

Nor this:

http
200 OK
Cache-Control: ...

It changed how many requests are carried over a connection.

Instead of:

text
several connections
each mostly sequential

we got:

text
one connection
many concurrent streams

That is multiplexing.

And it fundamentally changed the frontend network waterfall.