Streams

Streams process data chunk by chunk. response.body is a ReadableStream of bytes; a WritableStream is a destination; a TransformStream sits between. pipeThrough() chains transforms, pipeTo() ends in a sink, and tee() splits a stream. Pipes apply backpressure: a full sink queue stops the source. Streams are Baseline Widely available (since December 2024), as is CompressionStream for gzip and deflate.

A gzip round trip through a pipe chainHTMLLive
<pre id="out" style="font: 15px monospace"></pre>
<script type="module">
  const text = 'Streams deliver data in chunks. '.repeat(500);
  const zipped = await new Response(
    new Blob([text]).stream().pipeThrough(new CompressionStream('gzip'))).bytes();
  let chunks = 0, chars = 0;
  await new Blob([zipped]).stream()
    .pipeThrough(new DecompressionStream('gzip'))
    .pipeThrough(new TextDecoderStream())                        // bytes -> strings
    .pipeThrough(new TransformStream({ transform: (s, ctl) => ctl.enqueue(s.toUpperCase()) }))
    .pipeTo(new WritableStream({ write(chunk) { chunks++; chars += chunk.length; } }));
  out.textContent = `${text.length} chars -> ${zipped.length} gzip bytes\n`
    + `unzipped: ${chars} chars in ${chunks} chunk(s)`;
</script>
Browser output of Listing 9.4
Browser output of 4

To show a download progressively, loop on reader.read() until done; for await over a stream is not yet Baseline.