Representative interview topic

Frontend Interview: How would you use Blob.bytes() for binary uploads with an old-browser fallback?

FrontendMedium
Offer.cc Editorial TeamPublished Updated

Question

You must upload large files and compute a digest in the browser. New browsers support Blob.bytes(), but older browsers may not. Design reading, chunking, fallback, cancellation, error handling, and compatibility validation.

Prompt and scope

You must upload large files and compute a digest in the browser. New browsers support Blob.bytes(), but older browsers may not. Design reading, chunking, fallback, cancellation, error handling, and compatibility validation.

MDN marks Blob.bytes() Baseline 2026: it returns a Promise that resolves to a Uint8Array containing the Blob data and is available in Web Workers. The interview tests API semantics and resource boundaries; supporting a new method is not a complete upload design.

What the interviewer evaluates

  • Accurately describing the Promise and Uint8Array result without calling it a stream.
  • Recognizing the memory peak of reading a whole Blob and designing chunks or a stream path.
  • Using feature detection with arrayBuffer() or stream() fallbacks instead of browser-name checks.
  • Handling cancellation, retries, digest state, worker messaging, and user feedback.
  • Proving the design with a compatibility matrix and large-file stress tests.

Clarifying questions

  • What are file-size limits, upload concurrency, target browsers, and Worker availability?
  • What digest algorithm, server chunk protocol, resume semantics, and duplicate-chunk policy apply?
  • Must a complete digest exist before upload, or can the client upload while reading and verify at the end?
  • Can a failed transfer resume from confirmed chunks, and how is server idempotency defined?
  • What happens when a user navigates away, closes the tab, or the device is under memory pressure?

API semantics and read paths

Blob.bytes() takes no arguments and returns a Promise. The fulfilled value is a Uint8Array; a read failure rejects the Promise. It hands the Blob contents to the caller as one byte array, so it does not prove zero-copy behavior or unlimited large-file capacity. Read small files in a Worker if useful; for large files, prefer slice() chunks followed by per-chunk reading and upload.

Feature-detect the path: use bytes() when available, otherwise use arrayBuffer() and create a Uint8Array; where browser and protocol support it, consume stream() incrementally. Fallbacks must preserve chunk numbering, digest input, and error contracts so server validation does not change with the API.

Memory, chunks, and digests

Reading a whole Blob creates a peak at least on the order of the file size, plus upload buffers, decoding, and runtime overhead. Call slice(start, end) with fixed or adaptive bounds and retain only the current chunk and a bounded upload queue. Feed the digest in file order; parallel uploads must not reorder digest input.

Each chunk carries a file ID, version, index, length, and content digest. The server idempotently stores by file ID and index, then assembles in order and verifies total length and the full-file digest. Chunk digests do not replace an end-to-end digest because loss, reordering, or incorrect concatenation can still produce a wrong file.

Cancellation, retries, and workers

Pass an AbortController signal to reads and upload requests; cancellation clears queued chunks and releases references. Retry only recoverable errors with exponential backoff and an idempotent chunk key. Authentication expiry should pause for reauthorization, not retry forever. If a Worker computes the digest, the main thread receives progress, errors, and the final result instead of copying the entire byte array back.

With stream(), respect backpressure: the reader must not outrun the network and digest consumer. Every path records confirmed chunks, read and upload durations, retries, cancellation reasons, and an estimated memory peak, without logging file contents or sensitive paths.

Compatibility and security boundaries

Feature detection can check typeof Blob !== "undefined" and "bytes" in Blob.prototype before selecting bytes(). Do not rely only on User-Agent. Older browsers can fall back to arrayBuffer() or a controlled FileReader, and should receive an explicit message when the memory budget cannot be met.

Client digests provide integrity evidence, not authorization, malware scanning, or content-type validation. The server must limit file size, chunk size, index range, and total duration; a client MIME type is not a security decision. Avoid copying sensitive data across workers and release references promptly after completion.

Failure drills and validation checklist

Cover browsers with and without bytes(), Worker and main-thread paths, empty files, one-chunk and cross-chunk files, very large files, network interruption, cancel-and-resume, duplicate chunks, out-of-order chunks, and digest mismatch. Stress tests record p95 read time, upload throughput, peak memory, long tasks, failure rate, and recovery time.

If bytes() rejects, preserve chunk state and switch to an explicit fallback. If the fallback exceeds the memory budget, stop with a next-step message instead of forcing a full read. If the server detects a chunk or full digest mismatch, discard the unconfirmed assembly and resume from the last consistent chunk.

Follow-up questions and reference answers

How do you choose between bytes() and arrayBuffer()?

Both can load the entire Blob into memory. bytes() directly supplies a Uint8Array, useful for byte-oriented code, but does not automatically provide streaming. Large files should use chunks or a stream path.

Why is a client-only full-file digest insufficient?

It cannot prove that the server received every chunk in order, and it does not replace authorization or content safety checks. Verify chunk indexes, chunk digests, total length, and the server’s final digest.

How do you validate the old-browser fallback?

Force both capability paths with feature detection, then test a real browser matrix, Worker and main-thread execution, memory pressure, offline recovery, and cancellation. A single modern browser is insufficient.

Public sources

Related questions