tezvyn:

Download a large file via fetch and track ReadableStream progress

AI-drafted, machine-checkedSource: developer.mozilla.orgadvanced
Download a large file via fetch and track ReadableStream progress

It tests streaming I/O and backpressure beyond Promise-based fetch. Acquire a reader from response.body, loop read() until done, sum chunk lengths against Content-Length, and emit progress.

WHAT THIS TESTS: The interviewer wants to know if you can work with low-level streaming primitives instead of high-level convenience methods. Fetch returns a ReadableStream in response.body, and consuming it correctly requires understanding readers, chunk-based iteration, stream locking, and backpressure. Senior candidates should demonstrate that they know how to avoid blocking the main thread or exhausting memory when handling multi-gigabyte payloads, and they should mention that ReadableStream implements the async iterable protocol as an alternative to manual reader management.

A GOOD ANSWER COVERS: A strong response walks through five steps in order. First, validate the response status and read the Content-Length header to establish the total byte budget. Second, obtain a reader by calling response.body.getReader, which locks the stream so no other consumer can interfere. Third, create a read loop that repeatedly awaits reader.read and destructures the done boolean and value Uint8Array. Fourth, accumulate the byte count from each chunk length, calculate the ratio against Content-Length, and push that percentage to the UI via callbacks or a reactive stream. Fifth, handle cleanup by releasing the reader lock when the loop terminates or when an abort signal fires, and surface any network or decoding errors to the user. Mentioning the for await of syntax as a modern alternative shows extra depth, since ReadableStream is async iterable.

COMMON WRONG ANSWERS: The biggest red flag is immediately calling response.text, response.blob, or response.arrayBuffer. These methods consume the entire stream internally and give you no hook for per-chunk progress. Another mistake is forgetting that getReader locks the stream; attempting to pipe or tee afterward throws a TypeError. Some candidates also ignore backpressure by processing chunks synchronously inside the read loop without yielding to the event loop, which can jank the UI on large files. Finally, failing to check Content-Length before calculating progress leaves you without a denominator, and neglecting to handle reader cancellation means the download continues in the background even after the user navigates away.

LIKELY FOLLOW-UPS: The interviewer may ask how you would handle a response that uses chunked transfer encoding without a Content-Length header. They might also probe cancellation by asking how to abort the download mid-stream using an AbortController and reader.cancel. Another variant is asking how to tee the stream so you can simultaneously show progress and write the file to disk via a WritableStream or FileSystemWritableFileStream, or how to transform chunks on the fly using TransformStream.

ONE CONCRETE EXAMPLE: Imagine fetching a 500 MB video file. You call fetch with an AbortController signal, then check the Content-Length header to get roughly 524288000 bytes. You lock the stream by assigning response.body.getReader to a reader variable. Inside a while loop, you destructure done and value from awaiting reader.read. If value exists, you add value.length to a received variable and set progress to received divided by total. You update a progress bar element each iteration. When done is true, you close the reader. If the user clicks cancel, you call controller.abort and await reader.cancel to free the underlying connection.

Source: developer.mozilla.org

Read the original → developer.mozilla.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.