Stop waiting for JSON.parse.
Render rows while bytes are still arriving.
A live, head-to-head benchmark against a real ~5 MB JSON payload. Both panes pull the same bytes over the same network — only when those bytes become visible UI differs.
~5 MB · array of objects
Classic
fetch + JSON.parse
await fetch(url).then(r => r.json()) — cards render once.
Time to first item—When UI saw row #1
Items rendered0
Total time—
Bytes received0 B
Time to first byte—
StatusIdle
Cardsshowing 0 of 0
Press Run to start
Streaming
fetchstream-js
fetchStream(url).live(setSnap) — cards grow as bytes arrive.
Time to first item—When UI saw row #1
Items rendered0
Total time—
Bytes received0 B
Time to first byte—
StatusIdle
Cardsshowing 0 of 0
Press Run to start
Run the benchmark to see how much sooner streaming gives you the first visible row. Total transfer time is similar — that's network-bound — but time-to-first-paint is where streaming wins.