Experiments / 01

The Request Queue

Why isn’t loading 30 images just 30 requests?

  • Intermediate
  • 8 min
  • Impact ●●●

The problem

A page with 30 images doesn’t make 30 requests at the same moment. Something decides how many are in flight, how many wait, and what each one has to do before a single byte arrives. Lighthouse will tell you “you have too many requests”. It won’t tell you which part of the cost is the requests.

Every request pays for some mix of waiting for a connection, setting that connection up, a round trip to the server and moving the bytes. Which of those dominates depends on the protocol and on the shape of the page. The simulator below lets you change both.

Experiment

Protocol
30
80 KB
120 ms
25 Mbps
6
Load time
1.60 s
Connections opened
6
Avg wait in queue
797 ms
Peak in flight
6
Browser0 queued · 0 in flight · 30 done
conn 1idle
conn 2idle
conn 3idle
conn 4idle
conn 5idle
conn 6idle
Network
  • Queued
  • DNS
  • TCP
  • TLS
  • Waiting (TTFB)
  • Download
1.60 s
Same page, other protocols
  • HTTP/1.11.60 s
  • HTTP/21.30 s
  • HTTP/31.18 s

30 requests over 6 connections means 5 waves. A request after the first wave waits for a free connection; the average wait here is 797 ms.

Time splits between round trips and moving bytes (50% is bandwidth). Both kinds of optimisation would help.

30 resources · 2.4 MB total · simplified model, see assumptions below

Things to try

  1. Watch the waves. On HTTP/1.1 with 30 resources and 6 connections, look at the hatched “queued” bars. Requests 7–12 can’t start until a connection frees up. That is five waves of six.
  2. Change the six. Drag “HTTP/1.1 connections” to 2, then to 12. The six was never a law of nature; it’s a number browsers settled on.
  3. Switch to HTTP/2. The queue disappears and one connection carries every stream. Look at the first request: the DNS, TCP and TLS bars are paid once, not six times in parallel.
  4. Make the files huge. Set the average size near 1 MB. The three protocols converge, because now the bottleneck is the pipe, and the dashed bandwidth floor sits close to the end of the waterfall. Multiplexing can’t make a link faster.
  5. Make the network bad. Choose “Slow mobile” and compare HTTP/2 with HTTP/3. Every round trip you save now costs hundreds of milliseconds.
  6. Reuse the connection. Tick “Connection already open”. The setup phases vanish. This is what preconnect and keep-alive buy you.

Common misconception

“Browsers only load six resources at once.”

Not quite. It’s a useful observation about one specific situation.

The number comes from HTTP/1.1. A connection can carry only one response at a time, so the only way to download in parallel is to open more connections. The original spec suggested two per server; later specs dropped a fixed number and browsers settled on six per host, a compromise between parallelism and the cost of every extra connection.

That “six” is a per-origin, HTTP/1.x-era figure. It stops being the right mental model when:

  • the page is served over HTTP/2 or HTTP/3. Many requests share one connection as independent streams, so the six-connection limit isn’t the constraint. Servers advertise how many streams may be open at once, commonly 100 or more.
  • resources come from several origins. Each origin has its own connections and its own setup cost.
  • the browser prioritises requests. It may hold low-priority ones back so critical CSS and scripts aren’t competing for bandwidth.

This is also why domain sharding (spreading assets over img1., img2.… to beat the limit) was a real HTTP/1.1 trick and is usually a mistake today. It adds DNS lookups and connection setups, and it splits what HTTP/2 would have prioritised on one connection.

What each colour means

Queued
The request exists but can’t start. On HTTP/1.1 it’s waiting for a free connection. On HTTP/2 and HTTP/3 the early requests are waiting for the one connection to be ready.
DNS
Turning the hostname into an IP address. Paid once per origin; often cached, so on a repeat visit it can be near zero. Here it costs one round trip.
TCP
The three-way handshake. One round trip before any data can be sent. HTTP/3 doesn’t use TCP, so this bar disappears.
TLS
Agreeing encryption keys. With TLS 1.3 this is one more round trip on top of TCP. HTTP/3 runs over QUIC, which performs transport and TLS setup together, so a new HTTP/3 connection costs one round trip where HTTP/2 costs two.
Waiting (TTFB)
Sending the request and waiting for the first byte back: one round trip plus the server’s own processing time. This is the part latency punishes most, and the part multiplexing overlaps.
Download
Moving the bytes. Active downloads share the bandwidth, which is why six parallel downloads each look slower than one alone, while the total stays the same.

Trade-offs, and when this matters

  • “More requests are bad” is an outdated oversimplification. On HTTP/2 and HTTP/3 a request costs far less than it did, so bundling everything into one file is no longer an automatic win. Small, separately cacheable files can outperform one big bundle that is invalidated on every release.
  • Requests aren’t free. Each still carries headers, scheduling and server work, and a thousand tiny requests will still hurt. Fewer and larger can still help compression and reduce overhead. It just isn’t the rule it used to be.
  • HTTP/2 has a weakness. It multiplexes streams over a single TCP connection, so one lost packet can stall every stream until it is retransmitted. HTTP/3 moves to QUIC, where loss affects only the stream it hit. On a clean network you may never notice; on lossy mobile connections it can matter.
  • The cheapest request is one you don’t make. Caching and keeping the connection warm often beat any protocol choice. For third-party origins you know you’ll need, <link rel="preconnect"> moves the DNS, TCP and TLS work earlier.

Measure before optimising. Your real pages, networks and servers won’t match this model.

See it on a real page

  1. Open DevTools, then the Network tab, and reload with the cache disabled.
  2. Right-click the column headers and enable Protocol. You’ll see h2, h3 or http/1.1 per request.
  3. Click a request and open Timing. You’ll find the same phases as above: queueing, stalled, DNS lookup, initial connection, SSL, waiting for server response, content download.
  4. Use the waterfall column to look for the hatched-bar pattern: a block of requests that start late for no reason you can see.

Model assumptions

What this simulation simplifies
  • All resources come from one origin, are requested at once, and are the same type. Sizes vary ±40% around the average.
  • DNS, TCP, TLS 1.3 and QUIC handshakes cost one round trip each. No session resumption or 0-RTT.
  • The server takes 20 ms per request and can serve any number in parallel.
  • Active downloads share bandwidth equally. There is no TCP slow start, congestion control, packet loss or request prioritisation.
  • HTTP/2 and HTTP/3 allow up to 100 concurrent streams. Header compression and framing overhead are ignored.
  • The bandwidth floor is the total bytes divided by bandwidth: the time with zero latency and perfect parallelism.

These keep the cause and effect clear. Real numbers will be messier, which is why you measure.