Introduction
The Streams Standard [STREAMS] defines ReadableStream, WritableStream, and TransformStream: class-based streams with chunk-at-a-time delivery. The Iterable Streams API [ITER-STREAMS] defines a bytes-only streaming model built directly on the ECMAScript iteration protocols: streams are AsyncIterable<Uint8Array[]>, iteration yields batches of chunks to amortize per-tick costs, and production goes through a Writer interface with an explicit byte budget and backpressure policies.
This specification bridges the two models from the web streams side. It defines:
-
A new reader mode —
getReader({ mode: "iter" })— that reads batches from anyReadableStreamand conforms to the iterable streams consumption model. -
A new readable stream controller type —
new ReadableStream({ type: "iter", start(writer) })— whose controller is an [ITER-STREAMS]Writer, providing the push model. -
A new writable stream controller type —
new WritableStream({ type: "iter", write(chunks) })— a batch-native sink: the defaultWritableStreammodel with byte-budget bookkeeping, whosewrite()callback receives coalescedUint8Array[]batches instead of single chunks. -
A new writer mode —
getWriter({ mode: "iter" })— that exposes the [ITER-STREAMS]Writerinterface over anyWritableStream. -
An
IterTransformStreamclass — shape-compatible withTransformStreamandpipeThrough(), purpose-built for the iter model — whose transform contract is the [ITER-STREAMS] transform contract. -
A fused, pull-through pipe: when both ends of a pipe are iter-type, piping uses the iterable streams model directly — lazy, batch-preserving-where-possible, with backpressure coupled end to end.
// (a) Batched reads from any ReadableStream const reader= rs. getReader({ mode: 'iter' }); for await ( const chunksof reader) { // chunks is Uint8Array[] } // (b) Push-model construction; the controller IS an iter-streams Writer const rs= new ReadableStream({ type: 'iter' , async start( writer) { if ( ! writer. writeSync( header)) await writer. write( header); await writer. end(); } }); // (c) Batch-native sink: write() receives Uint8Array[] batches const ws= new WritableStream({ type: 'iter' , async write( chunks) { await socket. writev( chunks); } });
Internally, the new controller and reader types are based on the iterable streams model, allowing implementations to take advantage of its performance characteristics. Because they are new controller and reader types, backwards compatibility with existing streams is preserved: every existing operation on an iter-type stream works through compatibility facades, and every existing stream gains batched reading without modification.
Goals
-
Batched consumption for all streams: Reading a
ReadableStreambatch-at-a-time amortizes async iteration cost regardless of how the stream was created. -
Full iterable-streams citizenship: Objects defined by this specification conform structurally to the [ITER-STREAMS] interfaces and protocols. An iter reader is a
ByteReadableStream; the iter readable controller and the iter writer implementWriter; the protocol symbols are honored. Web streams participate in the iterable streams ecosystem —Stream.pull(),Stream.pipeTo(),Stream.text(), transforms — without adapters. -
Backwards compatibility: An iter-type stream is a
ReadableStream(orWritableStream). Default readers, default writers,tee(), piping, and every other existing operation continue to work. -
Pull-through piping: When both ends of a pipe are iter-type, the pipe is the iterable streams model: lazy, fused, and driven by the ultimate consumer.
-
Bytes-only where it matters, generic where it helps: Iter-type streams are bytes-only, matching [ITER-STREAMS]. The iter reader is generic: on a value-oriented stream it still provides batching-as-amortization, without claiming iterable-streams integration.
Non-Goals
-
Modifying the Iterable Streams API: [ITER-STREAMS] remains a separate specification. This specification consumes its interfaces and protocols; it defines nothing on the
Streamnamespace. -
Replacing default or byte streams: The default and
"bytes"stream types are untouched. This specification adds a third type alongside them. -
New consumption utilities: Draining helpers (
text(),bytes(), etc.) belong to [ITER-STREAMS]. This specification makes web streams work with them rather than duplicating them. -
BYOB integration: The
"byob"reader mode and iter-type streams do not interact.getReader({ mode: "byob" })on an iter-type stream throws, exactly as it does on a default stream.
Relationship to Existing Specifications
-
Streams Standard [STREAMS]: This specification extends the Streams Standard with new reader, writer, and controller types, and amends several of its algorithms and IDL definitions. See § 15 Modifications to the Streams Standard. The Streams Standard is a normative dependency.
-
Iterable Streams API [ITER-STREAMS]: Defines the
Writerinterface,ByteReadableStreamstructural type, byte budget and backpressure policy model, transform contract, and protocol symbols that this specification’s types implement. A normative dependency.
Note: This specification is intended for standardization through ECMA TC55 (WinterTC), not through the WHATWG. Because Web IDL provides no mechanism for extending enumerations from outside a specification, the changes to the Streams Standard are expressed as amendments in § 15 Modifications to the Streams Standard. If the extensions prove successful, upstreaming some or all of them into the Streams Standard would be a desirable outcome; the design deliberately confines the amendments to well-isolated extension points (new enum values, reserved dictionary members, and type-dispatched algorithm steps) to keep that path open.
Design Rationale
The shape of the integration
Each surface adopts whichever model fits its direction:
| Web streams side | Model | |
|---|---|---|
| Producing into a readable | ReadableStreamIterController
| implements the [ITER-STREAMS] Writer interface
|
| Consuming a readable | ReadableStreamIterReader
| is a ByteReadableStream (AsyncIterable<Uint8Array[]>)
|
| Producing into a writable | WritableStreamIterWriter
| implements the [ITER-STREAMS] Writer interface
|
| Consuming from a writable | underlying sink with type: "iter"
| the Streams Standard sink model, batch-widened: write() receives Uint8Array[]
|
[ITER-STREAMS] states that Writer "is an interface, not a concrete class — any object implementing this interface can serve as a writer," and that its stream types are structural (AsyncIterable<Uint8Array[]>). The production surfaces defined here are those objects — the controller handed to an underlying source’s start() is a Writer, with no wrapping and no adapter layer. The sink side deliberately keeps the Streams Standard’s callback model: an iter writable stream is a default WritableStream in every respect except that its bookkeeping is the byte-budget model and its write() callback receives coalesced batches. The sink lifecycle — one write at a time, promise-gated, close() and abort() callbacks — is inherited, not reinvented.
Why the integration needs no changes to [ITER-STREAMS]
Three properties of [ITER-STREAMS] carry the integration:
-
Stream.from()consultsSymbol.for('Stream.toAsyncStreamable')before the iteration protocols. This specification installs that hook onReadableStream.prototype(§ 10 The toAsyncStreamable hook), so every iterable-streams entry point —Stream.from(),Stream.pull(),Stream.text(),Stream.pipeTo()— automatically upgrades anyReadableStreamto batched reads. Without the hook, web streams still work through theSymbol.asyncIteratorfallback, but degrade to single-chunk batches. -
Stream.pipeTo()duck-types its destination on thewritemethod (preferringwritev). The controllers and writers defined here satisfy it structurally, so they are valid iterable-streams pipe destinations with batching, close, and error propagation intact. -
The
Symbol.for('Stream.drainableProtocol')symbol makesStream.ondrain()work with any object that carries it. TheWriter-implementing objects defined here carry it.
Batch boundaries are not semantic
Batching exists to amortize iteration costs. It carries no meaning: any operation may split, merge, or regroup batches, provided the flattened chunk sequence and its ordering are preserved (§ 5.1 Batch boundaries are not semantic). This principle is what makes the compatibility facades and the fused pipe observationally coherent: unbatching for a default reader, re-coalescing at a sink, and end-to-end fusion all preserve the only thing that matters — the chunks and their order.
Copyright
© 2026 Ecma International
Permission under Ecma’s copyright to copy, modify, prepare derivative works of, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the full text of this copyright notice on ALL copies of the work or portions thereof.
THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
1. Scope
This proposal defines the Iterable Web Streams Extensions: an extension of the Streams Standard [STREAMS] that integrates it with the Iterable Streams API [ITER-STREAMS]. It specifies:
-
A
ReadableStreamIterReaderacquired viagetReader({ mode: "iter" }), providing batched reads from anyReadableStream. -
A
ReadableStreamIterController, implementing the [ITER-STREAMS]Writerinterface, for push-model readable streams created withtype: "iter". -
A
WritableStreamIterControllerand a batch-widened underlying sink contract, for batch-native writable sinks created withtype: "iter": the Streams Standard sink model withwrite()receivingUint8Array[]batches and byte-budget bookkeeping. -
A
WritableStreamIterWriteracquired viagetWriter({ mode: "iter" }), implementing the [ITER-STREAMS]Writerinterface over anyWritableStream. -
An
IterTransformStreamclass, conforming to theReadableWritablePairshape, whose transform contract is the [ITER-STREAMS] transform contract. -
Amendments to the Streams Standard: new enum values, batch-aware
ReadableStream.from(), thetoAsyncStreamableprototype hook, and a type-dispatched pipe algorithm with a fused pull-through path.
2. Conformance
A conforming implementation of this specification must also be a conforming implementation of the Streams Standard [STREAMS] as amended by § 15 Modifications to the Streams Standard, and must provide the [ITER-STREAMS] interfaces and protocol symbols to the extent this specification depends on them.
Note: An implementation need not expose the [ITER-STREAMS] Stream namespace to conform to this specification — the dependency is on the Writer interface contract, the structural stream types, the backpressure model, the transform contract, and the protocol symbols. In practice the two specifications are designed to be implemented together.
A conforming implementation shall also conform to [ECMASCRIPT] and [WEBIDL].
3. Normative references
The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document.
References
Normative References
- [DOM]
- Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
- [ECMASCRIPT]
- ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
- [ITER-STREAMS]
- James M Snell. Iterable Streams API. Draft Proposal. URL: https://iter-streams.proposal.wintertc.org/
- [STREAMS]
- Adam Rice; et al. Streams Standard. Living Standard. URL: https://streams.spec.whatwg.org/
- [WEBIDL]
- Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
4. Terms and definitions
For the purposes of this document, the terms and definitions given in [ECMASCRIPT], the Streams Standard [STREAMS], the Iterable Streams API [ITER-STREAMS], and the following apply.
4.1. Iterable Web Streams Extensions
the extensions to the Streams Standard defined by this specification
4.2. batch
an array of chunks delivered as a single iteration step or read result; for byte-oriented streams, a Uint8Array[] as defined by the [ITER-STREAMS] batched chunks concept
4.3. iter readable stream
a ReadableStream whose controller is a ReadableStreamIterController
4.4. iter writable stream
a WritableStream whose controller is a WritableStreamIterController
4.5. facade
the adaptation layer through which existing Streams Standard operations (default readers, default writers, and the algorithms built on them) interoperate with iter-type streams
4.6. fused pipe
the pull-through pipe established when both ends of a pipe operation are iter-type streams, in which source batches are delivered directly to the destination sink’s write() callback with no intermediate buffering
5. Core concepts
5.1. Batch boundaries are not semantic
A batch is a delivery grouping, not a message boundary. Operations defined by this specification — and implementations, wherever this specification grants latitude — may split, merge, or regroup batches freely. The normative invariant is the flattened chunk sequence: the sequence of individual chunks obtained by concatenating batches in order. All operations MUST preserve the flattened chunk sequence and its ordering; none are required to preserve batch boundaries.
Note: This matches [ITER-STREAMS], in which batch composition is implementation-chosen and transforms regroup freely. Applications MUST NOT attach meaning to how chunks are grouped into batches.
5.2. Bytes-only types, generic reader
Iter readable streams and iter writable streams are bytes-only: their chunks are Uint8Array objects, and their production surfaces accept Uint8Array or strings (which are UTF-8 encoded), following the [ITER-STREAMS] Writer contract. Chunks of any other type are rejected with a TypeError.
The ReadableStreamIterReader, by contrast, is generic: it may be acquired on any ReadableStream and performs no chunk coercion. On a byte-carrying stream its batches are Uint8Array[] and the reader is a conforming [ITER-STREAMS] ByteReadableStream. On a value-oriented stream, batches are arrays of whatever the stream carries — batching still amortizes iteration cost, but the reader does not claim integration with the [ITER-STREAMS] byte-oriented utilities.
5.3. Internal state: the slots buffer
An iter-type stream’s internal state is the [ITER-STREAMS] model, not the Streams Standard’s chunk queue: a slots buffer of batches, a byte budget, and a buffered byte count, governed by a backpressure policy. Each write or writev occupies one slot; a slot’s byte size is the sum of its chunks' byte lengths.
The byte budget is configured through the stream’s queuing strategy: highWaterMark is the budget in bytes. If no strategy is provided, the budget is an implementation-defined default of at least 16384 bytes, mirroring [ITER-STREAMS]. A provided value below the implementation’s minimum MAY be clamped to that minimum. A size function MUST NOT be provided for iter-type streams; if present, the constructor throws a RangeError. Byte accounting is intrinsic.
Buffered bytes are decremented as chunks leave the buffer. When a facade consumes a slot partially (chunk at a time), the buffered byte count decreases per chunk as each chunk is consumed, not when the slot empties. This keeps producer-observable backpressure signals (canWrite, the drainable protocol) consistent between batch-native and facade consumption.
Note: The [ITER-STREAMS] overshoot rule — a write is accepted whenever buffered bytes are below the budget, and then counts fully even if it overshoots — means buffered bytes can exceed the budget. Through the default-writer facade this surfaces as a negative desiredSize, which is exactly the Streams Standard’s existing behavior for an over-full queue. The two models align without adjustment.
5.4. The compatibility invariant
Every existing Streams Standard operation works on iter-type streams through the facades:
| Stream | default reader / writer | byob reader | iter reader / writer |
|---|---|---|---|
default ReadableStream
| existing behavior | TypeError (existing)
| adapt: drain queue into a batch |
byte ReadableStream
| existing behavior | existing behavior | adapt: drain queue into a batch |
| iter readable stream | adapt: unbatch (§ 8.4 The default reader facade) | TypeError
| native |
default WritableStream
| existing behavior | — | adapt: Writer over default machinery (§ 12.3 On any other WritableStream: adapted)
|
| iter writable stream | adapt: writes into the slots buffer (§ 11.4 The default writer facade) | — | native |
tee(), piping between mixed types, async iteration of the stream itself (which remains chunk-at-a-time for compatibility), and integration points in other specifications that consume ReadableStream or WritableStream all operate through the default facades and continue to work unchanged.
5.5. Fusion
When both ends of a pipe are iter-type, the pipe is not a pump loop between two buffers. It is a fused pipe: source batches are delivered directly to the destination sink’s write() callback, bypassing the destination’s buffer, and each write()’s settlement gates the next pull from the source — through any composed transforms, back to the origin producer’s byte budget. Data moves only at the pace of the ultimate consumer. See § 14 Piping.
6. Web IDL definitions
6.1. IterWriteOptions
dictionary {IterWriteOptions AbortSignal ; };signal
The IterWriteOptions dictionary mirrors the [ITER-STREAMS] WriteOptions dictionary.
6.2. The ReadableStreamIterReader interface
[Exposed=*]interface {ReadableStreamIterReader (constructor ReadableStream );stream Promise <ReadableStreamReadResult >read ();undefined releaseLock (); };ReadableStreamIterReader includes ReadableStreamGenericReader ;
The ReadableStreamIterReader interface provides batched reads. It is acquired via getReader({ mode: "iter" }) on any ReadableStream. See § 7 The iter reader.
6.3. The ReadableStreamIterController interface
[Exposed=*]interface {ReadableStreamIterController readonly attribute boolean ?;canWrite Promise <undefined >((write Uint8Array or USVString ),chunk optional IterWriteOptions = {});options Promise <undefined >(writev sequence <(Uint8Array or USVString )>,chunks optional IterWriteOptions = {});options boolean ((writeSync Uint8Array or USVString ));chunk boolean (writevSync sequence <(Uint8Array or USVString )>);chunks Promise <unsigned long long >(end optional IterWriteOptions = {});options long long ();endSync undefined (fail optional any ); };reason
The ReadableStreamIterController interface is the controller for iter readable streams. It implements the [ITER-STREAMS] Writer interface; its member semantics are those of the Writer interface, bound to the stream’s slots buffer. See § 8 Iter readable streams.
6.4. The WritableStreamIterController interface
[Exposed=*]interface {WritableStreamIterController readonly attribute AbortSignal ;signal undefined (error optional any ); };e
The WritableStreamIterController interface is the controller for iter writable streams, passed to the underlying sink’s callbacks. Its surface mirrors the Streams Standard’s WritableStreamDefaultController: error() errors the stream, and signal is aborted when the stream is aborted, allowing a sink engaged in long-running work to observe cancellation. The difference from the default controller is internal: the stream’s bookkeeping is the slots buffer and byte budget rather than the size-algorithm queue. See § 11 Iter writable streams.
6.5. The WritableStreamIterWriter interface
[Exposed=*]interface {WritableStreamIterWriter (constructor WritableStream );stream readonly attribute boolean ?;canWrite readonly attribute Promise <undefined >;closed Promise <undefined >((write Uint8Array or USVString ),chunk optional IterWriteOptions = {});options Promise <undefined >(writev sequence <(Uint8Array or USVString )>,chunks optional IterWriteOptions = {});options boolean ((writeSync Uint8Array or USVString ));chunk boolean (writevSync sequence <(Uint8Array or USVString )>);chunks Promise <unsigned long long >(end optional IterWriteOptions = {});options long long ();endSync undefined (fail optional any );reason undefined (); };releaseLock
The WritableStreamIterWriter interface implements the [ITER-STREAMS] Writer interface over a WritableStream. It is acquired via getWriter({ mode: "iter" }). See § 12 Iter writers.
6.6. The IterTransformStream interface
[Exposed=*]interface {IterTransformStream (constructor optional any ,transform optional IterTransformStreamOptions = {});options readonly attribute ReadableStream ;readable readonly attribute WritableStream ; };writable dictionary {IterTransformStreamOptions unsigned long long ;budget DOMString = "strict"; };backpressure
The IterTransformStream interface provides batch-native transforms. It conforms to the ReadableWritablePair shape and may be passed to pipeThrough(). The transform argument is typed any because the accepted values — a stateless transform function, a stateful transform object, or undefined — follow the [ITER-STREAMS] transform argument detection rules, which Web IDL cannot express as a single type. See § 13 Iter transform streams.
6.7. Options dictionaries
dictionary {WritableStreamGetWriterOptions DOMString ;mode DOMString ; };backpressure dictionary {ReadableStreamFromOptions DOMString ; };type partial dictionary UnderlyingSource {DOMString = "strict"; };backpressure partial dictionary UnderlyingSink {DOMString = "strict"; };backpressure
The backpressure members take [ITER-STREAMS] BackpressurePolicy values. They are consulted only when the corresponding type is "iter"; for other stream types they are ignored. For iter writable streams, only "strict" and "unbounded" are permitted; see § 11.3 Backpressure policy.
Note: BackpressurePolicy is defined by [ITER-STREAMS]. The members are declared as DOMString because the enumeration is defined in another specification; values are validated in prose.
6.8. Protocol conformance
Objects defined by this specification participate in the [ITER-STREAMS] protocol symbols:
-
ReadableStreamIterControllerandWritableStreamIterWritereach provide a method keyed bySymbol.for('Stream.drainableProtocol'), with the semantics defined forWriterobjects by [ITER-STREAMS]: it returns a promise resolvingtruewhen buffered bytes fall below the byte budget, resolvingfalseif the writer closes while waiting, and rejecting if the writer errors.Stream.ondrain()therefore works with both. -
Both
Writer-implementing interfaces provideSymbol.asyncDisposeandSymbol.disposewith the disposal semantics defined by [ITER-STREAMS] (dispose callsfail()with no argument; async dispose of a closing writer awaits the graceful drain). -
ReadableStreamIterReaderprovidesSymbol.asyncIterator, conforming to theByteReadableStreamstructural type when the underlying chunks areUint8Arrayobjects. -
ReadableStreamgains aSymbol.for('Stream.toAsyncStreamable')method; see § 10 The toAsyncStreamable hook.
7. The iter reader
7.1. Acquisition
A ReadableStreamIterReader is acquired by calling getReader({ mode: "iter" }) on any ReadableStream, regardless of the stream’s underlying source type, or by its constructor. Acquisition locks the stream, exactly as for other reader types: while the reader is active, locked is true and acquiring any other reader throws a TypeError.
Unlike mode: "byob", mode: "iter" does not constrain the stream’s controller type. The reader performs no chunk coercion; see § 5.2 Bytes-only types, generic reader.
7.2. Reading
read() method reads the next batch. It returns a promise for a ReadableStreamReadResult:
- If the stream is errored, the promise rejects with the stored error.
- If chunks are available — in the slots buffer for an iter readable stream, or in the internal queue for other stream types — the promise resolves with
{ value, done: false }, where value is an array containing all currently available chunks, drained from the stream, in order. For an iter readable stream, the array MAY correspond to one or more whole or partial slots; boundaries are not preserved (§ 5.1 Batch boundaries are not semantic). - Otherwise, if the stream is closed, the promise resolves with
{ value: undefined, done: true }. - Otherwise, the read participates in the stream’s normal demand signaling (for pull-based sources, a pull is requested) and the promise resolves with a batch containing at least one chunk once data becomes available, or with
{ value: undefined, done: true }if the stream closes first.
Draining all available chunks per read is the batching amortization: one promise resolution delivers everything buffered. Implementations MAY cap the drained byte size of a single batch at an implementation-defined limit.
Reads decrement the buffered byte count and notify drain waiters per § 5.3 Internal state: the slots buffer, propagating demand to the producer.
7.3. Async iteration
ReadableStreamIterReader is obtained via its Symbol.asyncIterator method. Its behavior:
next()performs the same operation asread(), returning its result as the iterator result object.return(reason)cancels the stream with reason (as if byreader.cancel(reason)), releases the lock, and resolves with a done result.throw(reason)behaves asreturn(reason)and then rejects with reason.
A consumer breaking out of for await...of therefore cancels the source, matching the [ITER-STREAMS] convention that a consumer that stops iterating tears the pipeline down to the source.
When the stream’s chunks are Uint8Array objects, the reader is a conforming ByteReadableStream: it may be passed directly to Stream.pull(), Stream.text(), Stream.pipeTo(), and any other [ITER-STREAMS] consumer.
7.4. Reader generics
ReadableStreamIterReader includes the Streams Standard’s generic reader behaviors: the closed promise and cancel(reason) behave as for a default reader. releaseLock() releases the lock; pending read promises reject with a TypeError, matching default reader semantics.
8. Iter readable streams
8.1. Construction
An iter readable stream is constructed with type: "iter":
const rs= new ReadableStream({ type: 'iter' , async start( writer) { // writer is the ReadableStreamIterController — an iter-streams Writer if ( ! writer. writeSync( chunk)) await writer. write( chunk); const n= writer. endSync(); if ( n< 0 ) await writer. end(); } }, { highWaterMark: 65536 });
Constructor rules, applied when the underlying source’s type is "iter":
-
startis required. If absent, throw aTypeError. Thestartcallback is the only mechanism for acquiring the controller; a stream that can never be written to or ended is unusable by construction. -
If
pullorautoAllocateChunkSizeis present, throw aTypeError. The pull model is provided byReadableStream.from()(§ 9 ReadableStream.from() in batch mode), not by the controller. -
cancelis permitted and is invoked per § 8.3 Cancellation. -
The queuing strategy provides the byte budget per § 5.3 Internal state: the slots buffer; a
sizefunction throws aRangeError. -
The underlying source’s
backpressuremember selects the [ITER-STREAMS] backpressure policy for the controller; the default is"strict". All four policies are permitted. -
startis invoked with theReadableStreamIterControlleras its argument. Ifstartthrows or its returned promise rejects, the stream is errored with the thrown value, matching existing underlying-source semantics.
8.2. The controller is a Writer
The ReadableStreamIterController implements the [ITER-STREAMS] Writer interface, bound to the stream:
-
The slots buffer is the stream’s internal state; the byte budget and backpressure policy are those configured at construction.
-
write(),writev(),writeSync(),writevSync(),end(),endSync(),fail(), andcanWritehave the semantics defined by [ITER-STREAMS] for theWriterinterface, including string encoding, the try-fallback pattern, atomic writev, the pending writes queue for"strict"and"unbounded", and the end sentinel. -
end()resolves, with the total bytes written, when the last batch (and end sentinel) has been consumed; the stream then closes. From the perspective of readers, closure is ordinary stream closure. -
fail(reason)errors the stream with reason; pending reads reject with reason. -
The controller carries the drainable protocol and disposal symbols per § 6.8 Protocol conformance.
Chunks are accepted zero-copy: a written Uint8Array is not copied or detached, matching [ITER-STREAMS]. Producers MUST NOT mutate a chunk after writing it; see § 16 Security considerations.
8.3. Cancellation
cancel(), a reader’s cancel, or iterator return):
- The slots buffer is discarded.
- The controller transitions to the errored state with the cancel reason: subsequent writes reject (or return
falsefrom sync variants),canWritereturnsnull, pending write promises reject, a pendingend()promise rejects, and drain waiters are notified with the reason per the [ITER-STREAMS]fail()semantics. - The underlying source’s
cancelcallback, if any, is invoked with the reason, per existing Streams Standard semantics.
This is the web-streams expression of the [ITER-STREAMS] rule that a consumer that stops iterating signals cancellation to the writer.
8.4. The default reader facade
Default readers (and every operation built on them: async iteration of the stream, tee(), mixed-type piping, and consumers in other specifications) interoperate with iter readable streams through the unbatching facade:
-
A default read takes the next single chunk, in order, from the front of the slots buffer — consuming slots progressively, with a cursor into a partially consumed slot.
-
Buffered bytes decrement per chunk (§ 5.3 Internal state: the slots buffer).
-
Closure (after the end sentinel) and errors surface as ordinary default-reader closure and errors.
The flattened chunk sequence observed through the facade is identical to the sequence observed through batch reads.
9. ReadableStream.from() in batch mode
ReadableStream.from() is amended to accept an options argument: ReadableStream.from(source, { type: "iter" }).
type option is "iter", batch-mode from performs the following:
- Let iterable be source, interpreted as an async iterable if it has
Symbol.asyncIterator, else as a sync iterable if it hasSymbol.iterator; otherwise throw aTypeError. -
Return a new iter readable stream whose batch sequence is produced by lazily iterating iterable:
- Each value yielded by iterable that is an array is interpreted as a batch: its elements are the chunks. Each element must be a
Uint8Array; otherwise the stream is errored with aTypeError. - Each yielded value that is a
Uint8Arrayis interpreted as a single-chunk batch. - Any other yielded value errors the stream with a
TypeError. - Iteration is demand-driven: at most one iteration step of iterable is outstanding at a time, and steps are taken only to satisfy reads. Implementations MAY read ahead up to the byte budget.
- When iterable completes, the stream closes. If iteration throws, the stream errors with the thrown value.
- If the stream is cancelled, the iterator’s
return()method is invoked, per existingReadableStream.from()semantics.
- Each value yielded by iterable that is an array is interpreted as a batch: its elements are the chunks. Each element must be a
When the type option is absent or undefined, ReadableStream.from() behaves exactly as currently specified (each yielded value is a single chunk of a default stream). No inspection-based batch detection is performed: an async iterable of Uint8Array[] passed without the option produces a default stream whose chunks are arrays, exactly as today.
Note: Batch-mode from() supplies the pull model for iter-type streams; type: "iter" construction with start supplies the push model. This mirrors the [ITER-STREAMS] division between Stream.from() and Stream.push(). Note the difference in element handling: Stream.from() normalizes forgivingly (strings encoded, buffers wrapped); batch-mode from() is strict, accepting only Uint8Array chunks. Applications wanting the forgiving behavior can compose the two specifications: ReadableStream.from(Stream.from(input), { type: "iter" }).
10. The toAsyncStreamable hook
ReadableStream.prototype gains a method keyed by Symbol.for('Stream.toAsyncStreamable'):
ReadableStream stream:
- If stream is locked, throw a
TypeError. - Return the result of
getReader({ mode: "iter" })on stream.
Because [ITER-STREAMS] Stream.from() consults Symbol.for('Stream.toAsyncStreamable') before the iteration protocols, this single method upgrades every iterable-streams entry point to batched reads for any ReadableStream:
// All of these consume the ReadableStream via batched reads: await Stream. text( webReadableStream); Stream. pull( webReadableStream, gzip); await Stream. pipeTo( webReadableStream, writer);
Note: For value-oriented streams, the returned reader yields batches of non-byte values, which the [ITER-STREAMS] normalization rules will reject with a TypeError when consumed by its byte-oriented utilities — the same outcome as consuming such a stream through the Symbol.asyncIterator fallback.
11. Iter writable streams
11.1. Construction
An iter writable stream is constructed with type: "iter" in the underlying sink. The underlying sink’s type member is currently reserved by the Streams Standard (any value throws a RangeError); this specification defines its first value.
const ws= new WritableStream({ type: 'iter' , async write( chunks, controller) { // chunks is Uint8Array[] — every slot buffered at invocation time, coalesced await socket. writev( chunks); }, close() { return socket. close(); }, abort( reason) { socket. destroy( reason); } }, { highWaterMark: 65536 });
An iter writable stream is a default WritableStream with exactly two substitutions: its internal bookkeeping is the slots buffer and byte budget rather than the size-algorithm queue, and its write() callback receives a batch rather than a single chunk. The underlying sink contract — start, write, close, abort, all optional, with the Streams Standard’s invocation ordering and settlement gating — is otherwise inherited unchanged.
Constructor rules, applied when the underlying sink’s type is "iter":
-
The queuing strategy provides the byte budget per § 5.3 Internal state: the slots buffer; a
sizefunction throws aRangeError. -
The underlying sink’s
backpressuremember selects the policy; only"strict"and"unbounded"are permitted —"drop-oldest"and"drop-newest"throw aRangeError. See § 11.3 Backpressure policy. -
Sink callbacks are invoked with the
WritableStreamIterControlleras their controller argument.
11.2. Batch delivery
The sink’s write() callback is invoked with a batch: an array containing all chunks currently in the slots buffer — every available slot drained and concatenated in order. Boundaries are not preserved (§ 5.1 Batch boundaries are not semantic). Implementations MAY cap the byte size of a single delivered batch at an implementation-defined limit.
The Streams Standard’s sink sequencing is retained: one write() invocation at a time, with the returned promise gating the next. This gating is precisely where batching is regained: while a write() is pending, arriving chunks — whether written batch-at-a-time by an iter writer or chunk-at-a-time through the default writer facade — accumulate in the slots buffer, and the next invocation receives them all.
The remaining lifecycle is the Streams Standard’s, unchanged: close() is invoked after the end sentinel is reached and the final write() has settled, and its settlement fulfills the close request; abort(reason) is invoked per the standard abort sequencing; a rejected write() or a call to error() errors the stream.
During a fused pipe, write() is invoked with batches delivered directly from the pipe’s source rather than from the slots buffer; see § 14 Piping.
11.3. Backpressure policy
Iter writable streams support only the "strict" and "unbounded" policies. The dropping policies are excluded: data written to a WritableStream is committed toward a sink, and silently discarding committed data is not a meaningful sink behavior. (The dropping policies remain available where [ITER-STREAMS] defines them — push streams and broadcasts — and on iter readable streams, whose controller is a push-model writer.)
The policy is a property of the stream, configured at construction. It governs all producers: iter writers natively, and default writers through the facade.
11.4. The default writer facade
Default writers (and every operation built on them, including mixed-type piping) interoperate with iter writable streams through the facade:
-
write(chunk)accepts aUint8Arrayor a string (UTF-8 encoded); any other chunk rejects with aTypeError. Accepted chunks enter the slots buffer as single-chunk slots, subject to the budget and policy. -
desiredSizeis the byte budget minus buffered bytes (possibly negative).readyresolves when buffered bytes are below the budget, cycling per the Streams Standard’s conventions; its transitions coincide with [ITER-STREAMS] drain notification. -
close()enqueues the end sentinel; the close promise fulfills per § 11.2 Batch delivery. -
abort(reason)aborts the stream: pending facade writes reject, and the sink’sabort()callback is invoked per the Streams Standard’s sequencing.
12. Iter writers
12.1. Acquisition
A WritableStreamIterWriter is acquired by calling getWriter({ mode: "iter" }) on any WritableStream, or by its constructor. Acquisition locks the stream exactly as acquiring a default writer does.
The backpressure option is permitted only when the stream is not an iter writable stream (see § 12.3 On any other WritableStream: adapted); on an iter writable stream the policy belongs to the stream, and specifying the option throws a TypeError.
12.2. On an iter writable stream: native
On an iter writable stream, the writer’s operations bind directly to the stream’s slots buffer, budget, and policy — the Writer semantics of [ITER-STREAMS] with no adaptation. writev() batches occupy single slots and reach the sink’s write() callback whole (subject to coalescing with adjacent slots). end() is equivalent to closing the stream and resolves with the total bytes written through this writer. fail(reason) aborts the stream.
12.3. On any other WritableStream: adapted
On a default WritableStream, the writer adapts the Writer contract onto the default machinery:
Writer surface
| Default WritableStream mechanism
|
|---|---|
canWrite
| true if desiredSize > 0; false if ≤ 0; null if the stream is closed, closing, or errored
|
| drainable protocol | derived from the ready promise, wrapped to the true / false (closed) / reject (errored) contract
|
write(chunk)
| strings UTF-8 encoded; forwarded as a single write |
writev(chunks)
| forwarded as sequential writes, in order; the returned promise settles when all have settled. Atomicity is best-effort: if a write fails mid-batch, the stream is already errored and no further chunks are written |
writeSync() / writevSync()
| if desiredSize > 0, forward (per write/writev above) and return true; otherwise return false and write nothing — the try-fallback signal
|
end()
| close(); resolves with total bytes written through this writer
|
endSync()
| returns −1 unless the writer is already closing or closed (sink close is asynchronous); the try-fallback signal to await end()
|
fail(reason)
| abort(reason). Iter-level pending write promises reject synchronously with reason; the abort itself settles per Streams Standard semantics
|
The backpressure option (default "strict") selects the admission policy the adapter applies in front of the stream’s queue: "strict" tolerates one un-awaited pending write past exhaustion before rejecting with a RangeError; "unbounded" queues without limit. The dropping policies throw a TypeError, per § 11.3 Backpressure policy.
Note: This adaptation is what makes Stream.pipeTo(source, transforms, ws.getWriter({ mode: "iter" })) fully correct for any WritableStream. A default writer half-satisfies the [ITER-STREAMS] pipe destination duck-type today (it has write but not writev, end, or fail), silently losing batching, close propagation, and error propagation. The iter writer completes the contract.
13. Iter transform streams
13.1. The IterTransformStream class
Batch-native transforms are provided by IterTransformStream: a purpose-built class that conforms to the ReadableWritablePair shape — readable and writable attributes — rather than extending or modifying TransformStream. This follows the platform’s established pattern for transform-shaped classes (CompressionStream, TextDecoderStream, and their siblings), and it means pipeThrough() accepts an IterTransformStream structurally.
// Stateful: an object with a transform method — // exactly an iter-streams stateful transform const ts= new IterTransformStream({ async * transform( source, { signal}) { // source is AsyncIterable<Uint8Array[] | null> — null is the flush signal for await ( const chunksof source) { if ( chunks=== null ) { yield finalize(); break ; } yield process( chunks); } } }); // Stateless: a bare function invoked once per batch — // exactly an iter-streams stateless transform const mapped= new IterTransformStream( ( chunks) => chunks=== null ? null : chunks. map( processChunk)); rs. pipeThrough( ts). pipeTo( ws);
Constructor rules:
-
The
transformargument is interpreted using the [ITER-STREAMS] transform argument detection rules, verbatim: a function is a stateless transform; an object with a function-valuedtransformproperty is a stateful transform;undefinedyields the identity transform (batch pass-through). Any other value throws aTypeError. -
readableis an iter readable stream andwritableis an iter writable stream — genuine stream instances, so the facades, iter readers and writers, and fused pipe dispatch all apply to them. -
The
budgetandbackpressureoptions govern the writable leg’s slots buffer, with the same semantics and the same"strict"/"unbounded"restriction as § 11.3 Backpressure policy. The readable leg needs no buffer of its own: output flows on demand (§ 13.3 Laziness and composition).
13.2. The transform contract
The contract is the [ITER-STREAMS] transform contract, unchanged:
-
Stateful — an object with a
transform(source, options)method: source is anAsyncIterable<Uint8Array[] | null>(the writable side’s data, with a finalnullflush signal appended after end-of-stream), options carries the requiredAbortSignal, and the return value is an async iterable whose yields are normalized per the [ITER-STREAMS] transform output rules and become the readable side’s batches. -
Stateless — a bare function
(chunks, options): invoked once per batch withUint8Array[], and once withnullas the flush signal; the return value is normalized per the same output rules.
Note: These are not merely compatible shapes; they are the same values. The object or function given to IterTransformStream may be passed, unchanged, to Stream.pull() or any other [ITER-STREAMS] API that accepts transforms — the two specifications converge on one contract by construction.
Cancellation flows through the contract’s signal: cancelling readable or aborting writable aborts the AbortSignal delivered in options and tears the legs down per the usual stream semantics. There are no separate start, flush, or cancel callbacks: startup work belongs to the transform itself, flush is the null signal, and cancellation is the signal.
13.3. Laziness and composition
The transform executes pull-through: no transform code runs until the readable side is consumed. The writable side’s slots buffer is drained only as the transform’s source iterable is pulled, which happens only as the transform’s output is pulled. Backpressure spans the transform: a slow consumer of the readable side propagates, through the transform, to the writable side’s budget and its producers.
In a chain of IterTransformStream stages connected by fused pipes, this composes into a single lazily evaluated pipeline — the [ITER-STREAMS] compose-transform-pipeline model expressed through web streams plumbing. See § 14 Piping.
14. Piping
14.1. Type dispatch
The Streams Standard’s pipe-to algorithm gains a type dispatch as its first step:
-
If the source is an iter readable stream and the destination is an iter writable stream, the pipe is a fused pipe, specified in § 14.2 The fused pipe.
-
Otherwise, the existing algorithm applies unchanged, acquiring a default reader and a default writer; the facades make it correct for every mixed combination.
pipeThrough() requires no changes: it is pipe-to plus returning the readable side, and each leg dispatches independently.
14.2. The fused pipe
- Lock rs and ws for the duration of the pipe, exactly as the existing algorithm does. Internally, rs is consumed as batches (as if through an iter reader).
- Deliver rs’s batches directly to ws’s sink: each batch is passed to the sink’s
write()callback, bypassing ws’s slots buffer entirely. Piped data does not enter ws’s buffer. - Each
write()’s settlement gates the next pull from rs: no batch is pulled while awrite()is pending, and pulling drains rs’s slots buffer and notifies its producer’s drain waiters. Backpressure is coupled end to end with no intermediate elasticity. - Batches may be split or merged in flight; the flattened chunk sequence is preserved (§ 5.1 Batch boundaries are not semantic).
-
Shutdown propagation, byte-for-byte with the existing algorithm’s constraints:
Event Default behavior With prevent*flagrs errors ws is aborted with the reason (the sink’s abort()callback is invoked); the pipe promise rejectspreventAbort: ws is left writable; subsequent writers feed its slots buffer normally; the pipe promise rejects rs closes ws is closed as if by a writer’s close(): after the final pipedwrite()settles, the sink’sclose()callback is invoked; the pipe promise fulfills after close fulfillmentpreventClose: ws is left writable and open; the pipe promise fulfills ws errors (a write()rejects;error()is called)rs is cancelled with the reason; the pipe promise rejects preventCancel: rs is not cancelled; the pipe promise rejects signal aborted as in the existing algorithm: error both sides with the abort reason, subject to preventAbort and preventCancel; the pipe promise rejects with the reason - On pipe completion for any reason that leaves ws writable, subsequently acquired writers feed ws’s slots buffer, whose batches flow to the same sink
write()callback — the sink observes one continuous sequence of invocations across pipe and non-pipe phases.
Note: Nothing in the fused pipe is a mere optimization license; the laziness is normative. An implementation MUST NOT eagerly drain the source into destination-side buffering during a fused pipe — the absence of intermediate elasticity is observable to the source-side producer through its budget, and it is the point.
Note: A chain such as rs.pipeThrough(a).pipeThrough(b).pipeTo(ws), with every stage iter-type, collapses hop by hop: each fused pipe delivers upstream batches directly to the next stage, and each iter transform connects its legs lazily (§ 13.3 Laziness and composition). The result is a single consumer-driven pipeline from ws’s sink back to rs’s producer budget, semantically equivalent to a single [ITER-STREAMS] pull pipeline.
14.3. Mixed-type pipes
Mixed-type pipes use the existing algorithm through the facades. Two consequences worth noting:
-
Piping any source into an iter writable stream recovers batching at the destination despite the chunk-at-a-time facade: chunks land in the slots buffer individually, and each sink
write()invocation receives all available slots coalesced (§ 11.2 Batch delivery). -
Piping a source of non-byte chunks into an iter writable stream errors the destination with a
TypeErrorat the first such chunk (the facade’s chunk contract), which then propagates per the existing algorithm’s error rules.
15. Modifications to the Streams Standard
This section enumerates the amendments this specification makes to [STREAMS]. A runtime implementing both specifications behaves as if the Streams Standard were modified as follows:
-
**
ReadableStreamReaderMode**: add the enumeration value"iter". -
**
getReader()**: when the options'modeis"iter", return a newReadableStreamIterReaderfor the stream (§ 7.1 Acquisition). No controller-type restriction applies. -
**
ReadableStreamType**: add the enumeration value"iter". -
**
ReadableStreamconstructor**: when the underlying source’stypeis"iter", set up aReadableStreamIterControllerper § 8.1 Construction, including thestart-required, no-pull, no-sizerules and thebackpressuremember. -
**
ReadableStream.from()**: accept a second argument, aReadableStreamFromOptions; when itstypeis"iter", behave per § 9 ReadableStream.from() in batch mode. -
**
ReadableStream.prototype**: add theSymbol.for('Stream.toAsyncStreamable')method defined in § 10 The toAsyncStreamable hook. -
**Underlying sink
type**: replace the unconditionalRangeErrorfor a presenttypemember with: if the value is"iter", set up aWritableStreamIterControllerper § 11.1 Construction; for any other non-undefinedvalue, throw aRangeErroras today. -
**
getWriter()**: accept an optionalWritableStreamGetWriterOptionsargument; whenmodeis"iter", return a newWritableStreamIterWriterper § 12 Iter writers.getWriter()with no arguments is unchanged. -
Pipe-to: prepend the type dispatch of § 14.1 Type dispatch; when both ends are iter-type, the pipe is the fused pipe of § 14.2 The fused pipe.
-
Default reader and writer interoperation with iter-type streams per § 8.4 The default reader facade and § 11.4 The default writer facade.
No other Streams Standard behavior is modified. In particular, async iteration of a ReadableStream itself remains chunk-at-a-time; tee() is unchanged (operating through the default facade on iter streams); the "bytes" type, BYOB machinery, and default streams are untouched; and TransformStream — including its reserved readableType and writableType transformer members — is not modified at all. Batch-native transforms are provided by the separate IterTransformStream class (§ 13 Iter transform streams), which conforms to the ReadableWritablePair shape rather than extending TransformStream.
16. Security considerations
-
Zero-copy sharing: Chunks pass through iter-type streams without copying or detaching. A producer that mutates a
Uint8Arrayafter writing it can observe or influence a consumer, and vice versa. This matches [ITER-STREAMS]; applications crossing trust boundaries should copy explicitly. This differs from the"bytes"stream type, which transfers buffers. -
Unbounded buffering: The
"unbounded"policy permits unlimited pending writes; producers using it are responsible for their own memory discipline, as in [ITER-STREAMS]. -
Budget as a signal: Byte budgets and drain timing are producer-observable. Implementations that adjust budgets dynamically (as [ITER-STREAMS] permits) should consider whether budget changes leak cross-origin or cross-tenant information in multi-tenant runtimes.
17. Open issues
17.1. Budget floor
This specification mirrors the [ITER-STREAMS] 16384-byte budget floor by permitting implementations to clamp smaller highWaterMark values. Whether small explicit budgets should instead be honored (useful for testing) is an open question for both specifications.
17.2. Upstreaming
The amendments in § 15 Modifications to the Streams Standard are confined to enum values, reserved dictionary members, and a type dispatch in pipe-to, specifically to keep an upstreaming path into [STREAMS] open. Whether and when to propose that is a process question outside this document.
Index
Terms defined by this specification
- async iterator, in § 7.3
-
backpressure
- dict-member for IterTransformStreamOptions, in § 6.6
- dict-member for UnderlyingSink, in § 6.7
- dict-member for UnderlyingSource, in § 6.7
- dict-member for WritableStreamGetWriterOptions, in § 6.7
- batch, in § 4.2
- batch-mode from, in § 9
- budget, in § 6.6
-
canWrite
- attribute for ReadableStreamIterController, in § 6.3
- attribute for WritableStreamIterWriter, in § 6.5
- closed, in § 6.5
- constructor(), in § 6.6
-
constructor(stream)
- constructor for ReadableStreamIterReader, in § 6.2
- constructor for WritableStreamIterWriter, in § 6.5
- constructor(transform), in § 6.6
- constructor(transform, options), in § 6.6
-
end()
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
end(options)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
endSync()
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
- error(), in § 6.4
- error(e), in § 6.4
- facade, in § 4.5
-
fail()
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
fail(reason)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
- flattened chunk sequence, in § 5.1
- fused pipe, in § 4.6
- Iterable Web Streams Extensions, in § 4.1
- iter readable stream, in § 4.3
- IterTransformStream, in § 6.6
- IterTransformStream(), in § 6.6
- IterTransformStreamOptions, in § 6.6
- IterTransformStream(transform), in § 6.6
- IterTransformStream(transform, options), in § 6.6
- iter writable stream, in § 4.4
- IterWriteOptions, in § 6.1
- mode, in § 6.7
- per chunk, in § 5.3
- read(), in § 7.2
- readable, in § 6.6
- ReadableStreamFromOptions, in § 6.7
- ReadableStreamIterController, in § 6.3
- ReadableStreamIterReader, in § 6.2
- ReadableStreamIterReader(stream), in § 6.2
- ReadableStream toAsyncStreamable method, in § 10
-
releaseLock()
- method for ReadableStreamIterReader, in § 7.4
- method for WritableStreamIterWriter, in § 6.5
-
signal
- attribute for WritableStreamIterController, in § 6.4
- dict-member for IterWriteOptions, in § 6.1
- slots buffer, in § 5.3
- type, in § 6.7
- writable, in § 6.6
- WritableStreamGetWriterOptions, in § 6.7
- WritableStreamIterController, in § 6.4
- WritableStreamIterWriter, in § 6.5
- WritableStreamIterWriter(stream), in § 6.5
-
write(chunk)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
write(chunk, options)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
writeSync(chunk)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
writev(chunks)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
writev(chunks, options)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
-
writevSync(chunks)
- method for ReadableStreamIterController, in § 6.3
- method for WritableStreamIterWriter, in § 6.5
Terms defined by reference
-
[DOM] defines the following terms:
- AbortSignal
-
[STREAMS] defines the following terms:
- ReadableStream
- ReadableStreamGenericReader
- ReadableStreamReadResult
- ReadableWritablePair
- TransformStream
- UnderlyingSink
- UnderlyingSource
- WritableStream
- cancel()
- highWaterMark
- locked
- pipeThrough(transform)
- size
-
[WEBIDL] defines the following terms:
- DOMString
- Promise
- RangeError
- TypeError
- USVString
- Uint8Array
- any
- boolean
- long long
- sequence
- undefined
- unsigned long long
IDL Index
dictionary {IterWriteOptions AbortSignal ; }; [Exposed=*]signal interface {ReadableStreamIterReader (constructor ReadableStream );stream Promise <ReadableStreamReadResult >read ();undefined releaseLock (); };ReadableStreamIterReader includes ReadableStreamGenericReader ; [Exposed=*]interface {ReadableStreamIterController readonly attribute boolean ?;canWrite Promise <undefined >((write Uint8Array or USVString ),chunk optional IterWriteOptions = {});options Promise <undefined >(writev sequence <(Uint8Array or USVString )>,chunks optional IterWriteOptions = {});options boolean ((writeSync Uint8Array or USVString ));chunk boolean (writevSync sequence <(Uint8Array or USVString )>);chunks Promise <unsigned long long >(end optional IterWriteOptions = {});options long long ();endSync undefined (fail optional any ); }; [Exposed=*]reason interface {WritableStreamIterController readonly attribute AbortSignal ;signal undefined (error optional any ); }; [Exposed=*]e interface {WritableStreamIterWriter (constructor WritableStream );stream readonly attribute boolean ?;canWrite readonly attribute Promise <undefined >;closed Promise <undefined >((write Uint8Array or USVString ),chunk optional IterWriteOptions = {});options Promise <undefined >(writev sequence <(Uint8Array or USVString )>,chunks optional IterWriteOptions = {});options boolean ((writeSync Uint8Array or USVString ));chunk boolean (writevSync sequence <(Uint8Array or USVString )>);chunks Promise <unsigned long long >(end optional IterWriteOptions = {});options long long ();endSync undefined (fail optional any );reason undefined (); }; [Exposed=*]releaseLock interface {IterTransformStream (constructor optional any ,transform optional IterTransformStreamOptions = {});options readonly attribute ReadableStream ;readable readonly attribute WritableStream ; };writable dictionary {IterTransformStreamOptions unsigned long long ;budget DOMString = "strict"; };backpressure dictionary {WritableStreamGetWriterOptions DOMString ;mode DOMString ; };backpressure dictionary {ReadableStreamFromOptions DOMString ; };type partial dictionary UnderlyingSource {DOMString = "strict"; };backpressure partial dictionary UnderlyingSink {DOMString = "strict"; };backpressure
Copyright & Software License
Ecma International
Rue du Rhone 114
CH-1204 Geneva
Tel: +41 22 849 6000
Fax: +41 22 849 6001
Web: https://ecma-international.org/
Copyright Notice
© 2026 Ecma International
This draft document may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this section are included on all such copies and derivative works. However, this document itself may not be modified in any way, including by removing the copyright notice or references to Ecma International, except as needed for the purpose of developing any document or deliverable produced by Ecma International.
This disclaimer is valid only prior to final version of this document. After approval all rights on the standard are reserved by Ecma International.
The limited permissions are granted through the standardization phase and will not be revoked by Ecma International or its successors or assigns during this time.
This document and the information contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Software License
All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.