Streaming and waterfalls
Three upstream calls with injected delays of 1200ms, 1800ms, 2400ms, arranged four different ways. The upstream figure on each panel is measured wall-clock time, so the arithmetic is checkable rather than asserted.
Sequential should total about 5400ms. Parallel should be about 2400ms — the slowest leg, not the sum.
What to check
Measure from the second request onward. The first request after pnpm start can serve build-warm data with timings that make no sense. This bit during development: one reading showed legs of 985ms, 27ms and 27ms before settling into the real numbers.
The waterfall. Compare the two panels in the first group. Same three delays; one totals about 5400ms and the other about 2400ms, purely because of Promise.all.
Boundary granularity. Watch groups 2 and 3 on a hard reload. One boundary means all three appear together at 2400ms. Three boundaries mean they appear at 1200ms, 1800ms and 2400ms — the first content lands twice as early for identical total work.
Memoization. Group 4 fetches one station from two sibling components. Both report roughly the same duration and the page does not take 5000ms, because only one HTTP request was made.
See it in the raw stream. curl -N --raw -s localhost:3000/streaming, or time the whole page with curl -s -o /dev/null -w '%{time_total}' localhost:3000/streaming.
1 · Sequential against parallel
Promise.all. They use different stations so neither can reuse the other’s in-flight requests.Sequential
suspense fallbackexpect about 5400ms
Parallel
suspense fallbackexpect about 2400ms
2 · One boundary for three slow things
All three together
suspense fallbackone fallback for all three — nothing appears until about 2400ms
3 · One boundary each
Item 1
suspense fallbackresolves at about 1200ms
Item 2
suspense fallbackresolves at about 1800ms
Item 3
suspense fallbackresolves at about 2400ms
4 · Memoized duplicates
fetch GETs are memoized for one render pass, so this costs one request, not two — and the page does not take 5000ms.First caller
suspense fallbackstarts the request
Second caller
suspense fallbackjoins the same request