Fetch Streaming Response Backpressure

Read a fetch response body as a stream with manual reader control, honoring backpressure so a slow consumer cannot balloon memory.

JavascriptData Fetching

Code

snippet
// stream the response body incrementally so backpressure applies
async function downloadWithProgress(url, onProgress, chunkPauseMs = 0) {
  const res = await fetch(url);
  if (!res.ok || !res.body) throw new Error('download failed: ' + res.status);

  const total = Number(res.headers.get('content-length') ?? 0);
  const reader = res.body.getReader();
  let received = 0;
  const parts = [];

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    parts.push(value);
    received += value.length;

    if (onProgress && total > 0) {
      onProgress(received, total);
    }
    if (chunkPauseMs > 0) {
      // 消费变慢时读取循环自然放慢,读取暂停即向上游传导背压
      await new Promise((r) => setTimeout(r, chunkPauseMs));
    }
  }

  const blob = new Blob(parts);
  return { bytes: received, total, blob };
}

const result = await downloadWithProgress(
  'https://cdn.example.com/dataset.bin',
  (got, total) => console.log('progress:', Math.round((got / total) * 100) + '%'),
  10,
);
console.log('downloaded', result.bytes, 'of', result.total, 'bytes');