Streaming Fetch: Reading response.body Before the Download Completes
The buffering is a habit, not a browser limit
Left column - The habit that blocks: - fetch() settles once headers arrive - response.json() waits for every byte - .text() too - one full string first - So the UI sees nothing until the end - Streaming has been available since 2016 Right column - Read as it lands: - response.body is a ReadableStream - getReader(), then loop on read() - {value, done} - Uint8Array chunks - Not calling read() slows the source - pipeThrough/pipeTo pass pressure on Why it matters: - First record lands before the end - Kills perceived lag on long responses - Buffering 50MB can hold 2-3x in RAM - Chunk by chunk bounds peak footprint - For lag alone, pagination is simpler The decode trap: - Decode with TextDecoder stream:true - Naive per-chunk decode splits UTF-8 - Arabic and emoji break at chunk edges - One split glyph corrupts the text The hard boundary - JSON is not incremental: - JSON is not self-delimiting - A partial document stays invalid - No useful record before the last brace - Use NDJSON - one record per line - Video is the opposite - streams natively Honest test - three runs: - Serve a slow NDJSON endpoint - Time first record: .json() vs getReader() - Reader wins at the first chunk, not the end - Emoji without stream:true breaks at edges - One big JSON object: nothing emerges early - It was the format, not the transport The wrong tool check: - One-way server push? Server-Sent Events - Two-way messaging? WebSocket - Resumable partial file? Range requests - Streaming fetch: one response, read early