← textStream() for response/request/blob
v151 · fileapi · member reference
Blob.textStream()
Reads a Blob (or File) as a ReadableStream of UTF-8-decoded strings — the streaming counterpart of blob.text(), defined in W3C FileAPI. Unlike the Body-mixin version, every call creates a fresh stream.
Syntax
// W3C FileAPI — Blob (normative IDL)
ReadableStream textStream();
// Call form
const stream = blob.textStream();
Chromium's binding: [RuntimeEnabled=TextStreamMethod, CallWith=ScriptState, NewObject, RaisesException] ReadableStream textStream(); in blob.idl.
Inputs
The method takes no parameters. Its only input is the blob's own byte sequence. Notably there is no encoding argument: FileAPI points out this differs from FileReader.readAsText(), which accepts an encoding label — textStream() always decodes UTF-8.
Outputs
Returns a ReadableStream whose chunks are strings: the result of the blob's get stream algorithm (a new ReadableStream created in the blob's relevant realm) piped through a TextDecoderStream set up with UTF-8.
An empty blob therefore yields an already-empty stream (no chunks), not an error.
Source: FileAPI — Blob.textStream() steps; FileAPI — Blob get stream algorithmErrors
No synchronous exceptions in the spec steps: unlike the Body-mixin version, FileAPI's textStream() steps define no throw paths — a blob can always produce a fresh stream. (Chromium's binding still carries RaisesException; treat that as an implementation detail, not a spec contract.)
Asynchronous stream failures: a File-backed blob can fail while being read. FileAPI defines exactly five failure reasons — NotFound, UnsafeFile, TooManyReads, SnapshotState, and FileLock — and a read that fails for one of these reasons errors the stream with that failure reason: pending and future read() promises reject. Handle rejection from the reader, not a try/catch around the call.
Not to be confused with FileReader errors: the NotFoundError-style DOMException names are FileAPI's mapping for the FileReader read methods (thrown by synchronous reads or surfaced via FileReader.error for asynchronous ones). A ReadableStream from textStream() is errored with the raw failure reason itself — do not test for DOMException names here.
Malformed bytes: as with the Body version, decoding is non-fatal by default (TextDecoderOptions.fatal defaults to false), so invalid UTF-8 yields U+FFFD replacement characters rather than an error.
Context
Receiver: any Blob, including File objects from file pickers (<input type="file">), drag-and-drop, the clipboard, or constructed blobs.
Exposure: Blob is exposed in both Window and Worker contexts (Chromium's blob.idl; the WPT suite is an .any.js running in window and worker). No secure-context requirement and no permission prompt for same-page blobs.
Availability: Chrome 151 per the milestone listing and BCD; gated at build time by the TextStreamMethod runtime feature (status stable at trunk).
Lifecycle
Repeatable, unlike Body: every call runs the blob's get stream algorithm, which creates a new ReadableStream. There is no bodyUsed and no “unusable” state — you may call textStream() many times, even concurrently, and each stream is independent.
Underlying mutability: a Blob's bytes are immutable for the page, but a File on disk can change or disappear between call and completion — that is exactly when the asynchronous failure reason path errors the stream (see Errors).
Stream lifetime: each returned stream follows ordinary pipe semantics (locked while read, closed at end).
Source: FileAPI — Blob get stream algorithm; FileAPI — failure reasonExamples
// Stream a user-picked file as decoded text chunks.
// (input is an <input type="file"> element)
const file = input.files[0];
const reader = file.textStream().getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
process(value); // value is a string, UTF-8 decoded
}
} catch (err) {
// Asynchronous read failure — e.g. the file changed on disk
// (FileAPI failure reason), not a malformed-bytes error.
console.error("read failed:", err);
}
Source: WPT Blob-textStream.any.js; FileAPI — Blob.textStream()
Compatibility
| Engine / runtime | Support | Notes |
|---|---|---|
| Chrome | 151 | Matches the Chrome 151 milestone listing (Enabled by default); Chrome for Android and WebView (Android + iOS) are BCD mirrors |
| Edge | mirror | BCD mirrors Chrome's data |
| Firefox | Not supported | BCD version_added: false (Firefox for Android mirrors); vendor signal recorded on the ChromeStatus entry: No signal |
| Safari | Not supported | BCD version_added: false (Safari on iOS mirrors); the ChromeStatus entry records a Positive signal — a recorded signal, not an official WebKit standards position (a feature this small has none) |
| Node.js | 26.5.0 | BCD records version_added: 26.5.0 |
| Deno | Unknown | No BCD entry as of 2026-07-26 |
Support rows are from BCD only. Separately, vendor signals come from the ChromeStatus API feature record (checked 2026-07-26): Firefox “No signal”, Safari “Positive”, web developers “No signals”. No Baseline entry: the webstatus.dev query returns no feature (checked 2026-07-26).
Source: BCD api/Blob.json; ChromeStatus API feature record; webstatus.dev querySecurity and privacy
No new authority: the method needs no permission or gesture beyond whatever produced the blob (a file picker's user selection, a constructed blob, drag-and-drop). It only reads bytes the page already holds.
Deterministic decoding: always UTF-8 — unlike readAsText(), no encoding label can be supplied or inherited, so the decoding contract cannot be renegotiated per blob; malformed bytes become U+FFFD replacement text rather than an exception channel.
Disclosure/storage: reading is local; nothing is transmitted or persisted by this method, and stream lifetime is bounded by the blob's own lifetime. File-backed reads can fail asynchronously if the underlying file changes — surface that failure to the user rather than silently truncating.
Source: FileAPI — Blob.textStream() steps and note; FileAPI — failure reason