This specification provides APIs for creating, composing, and consuming streams of data that map efficiently to low-level I/O primitives.

Using an identity transform stream as a primitive to create new readable streams

A writable stream with no backpressure or success signals

A readable byte stream with an underlying push source (no backpressure support)

A readable stream with an underlying push source and backpressure support

A readable stream with an underlying push source (no backpressure support)

Using streams in other specifications

1. Introduction

This section is non-normative. Large swathes of the web platform are built on streaming data: that is, data that is created, processed, and consumed in an incremental fashion, without ever reading all of it into memory. The Streams Standard provides a common set of APIs for creating and interfacing with such streaming data, embodied in readable streams, writable streams, and transform streams. These APIs have been designed to efficiently map to low-level I/O primitives, including specializations for byte streams where appropriate. They allow easy composition of multiple streams into pipe chains, or can be used directly via readers and writers. Finally, they are designed to automatically provide backpressure and queuing. This standard provides the base stream primitives which other parts of the web platform can use to expose their streaming data. For example, [FETCH] exposes Response bodies as ReadableStream instances. More generally, the platform is full of streaming abstractions waiting to be expressed as streams: multimedia streams, file streams, inter-global communication, and more benefit from being able to process data incrementally instead of buffering it all into memory and processing it in one go. By providing the foundation for these streams to be exposed to developers, the Streams Standard enables use cases like: Video effects: piping a readable video stream through a transform stream that applies effects in real time.

Decompression: piping a file stream through a transform stream that selectively decompresses files from a .tgz archive, turning them into img elements as the user scrolls through an image gallery.

Image decoding: piping an HTTP response stream through a transform stream that decodes bytes into bitmap data, and then through another transform that translates bitmaps into PNGs. If installed inside the fetch hook of a service worker, this would allow developers to transparently polyfill new image formats. [SERVICE-WORKERS] Web developers can also use the APIs described here to create their own streams, with the same APIs as those provided by the platform. Other developers can then transparently compose platform-provided streams with those supplied by libraries. In this way, the APIs described here provide unifying abstraction for all streams, encouraging an ecosystem to grow around these shared and composable interfaces.

2. Model

A chunk is a single piece of data that is written to or read from a stream. It can be of any type; streams can even contain chunks of different types. A chunk will often not be the most atomic unit of data for a given stream; for example a byte stream might contain chunks consisting of 16 KiB Uint8Array s, instead of single bytes.

2.1. Readable streams

A readable stream represents a source of data, from which you can read. In other words, data comes out of a readable stream. Concretely, a readable stream is an instance of the ReadableStream class.

Although a readable stream can be created with arbitrary behavior, most readable streams wrap a lower-level I/O source, called the underlying source . There are two types of underlying source: push sources and pull sources.

Push sources push data at you, whether or not you are listening for it. They may also provide a mechanism for pausing and resuming the flow of data. An example push source is a TCP socket, where data is constantly being pushed from the OS level, at a rate that can be controlled by changing the TCP window size.

Pull sources require you to request data from them. The data may be available synchronously, e.g. if it is held by the operating system’s in-memory buffers, or asynchronously, e.g. if it has to be read from disk. An example pull source is a file handle, where you seek to specific locations and read specific amounts.

Readable streams are designed to wrap both types of sources behind a single, unified interface. For web developer–created streams, the implementation details of a source are provided by an object with certain methods and properties that is passed to the ReadableStream() constructor.

Chunks are enqueued into the stream by the stream’s underlying source. They can then be read one at a time via the stream’s public interface, in particular by using a readable stream reader acquired using the stream’s getReader() method.

Code that reads from a readable stream using its public interface is known as a consumer .

Consumers also have the ability to cancel a readable stream, using its cancel() method. This indicates that the consumer has lost interest in the stream, and will immediately close the stream, throw away any queued chunks, and execute any cancellation mechanism of the underlying source.

Consumers can also tee a readable stream using its tee() method. This will lock the stream, making it no longer directly usable; however, it will create two new streams, called branches , which can be consumed independently.

For streams representing bytes, an extended version of the readable stream is provided to handle bytes efficiently, in particular by minimizing copies. The underlying source for such a readable stream is called an underlying byte source . A readable stream whose underlying source is an underlying byte source is sometimes called a readable byte stream . Consumers of a readable byte stream can acquire a BYOB reader using the stream’s getReader() method.

2.2. Writable streams

A writable stream represents a destination for data, into which you can write. In other words, data goes in to a writable stream. Concretely, a writable stream is an instance of the WritableStream class.

Analogously to readable streams, most writable streams wrap a lower-level I/O sink, called the underlying sink . Writable streams work to abstract away some of the complexity of the underlying sink, by queuing subsequent writes and only delivering them to the underlying sink one by one.

Chunks are written to the stream via its public interface, and are passed one at a time to the stream’s underlying sink. For web developer-created streams, the implementation details of the sink are provided by an object with certain methods that is passed to the WritableStream() constructor.

Code that writes into a writable stream using its public interface is known as a producer .

Producers also have the ability to abort a writable stream, using its abort() method. This indicates that the producer believes something has gone wrong, and that future writes should be discontinued. It puts the stream in an errored state, even without a signal from the underlying sink, and it discards all writes in the stream’s internal queue.

2.3. Transform streams

A transform stream consists of a pair of streams: a writable stream, known as its writable side , and a readable stream, known as its readable side . In a manner specific to the transform stream in question, writes to the writable side result in new data being made available for reading from the readable side.

Concretely, any object with a writable property and a readable property can serve as a transform stream. However, the standard TransformStream class makes it much easier to create such a pair that is properly entangled. It wraps a transformer , which defines algorithms for the specific transformation to be performed. For web developer–created streams, the implementation details of a transformer are provided by an object with certain methods and properties that is passed to the TransformStream() constructor. Other specifications might use the GenericTransformStream mixin to create classes with the same writable / readable property pair but other custom APIs layered on top.

An identity transform stream is a type of transform stream which forwards all chunks written to its writable side to its readable side, without any changes. This can be useful in a variety of scenarios. By default, the TransformStream constructor will create an identity transform stream, when no transform() method is present on the transformer object.

Some examples of potential transform streams include:

A GZIP compressor, to which uncompressed bytes are written and from which compressed bytes are read;

A video decoder, to which encoded bytes are written and from which uncompressed video frames are read;

A text decoder, to which bytes are written and from which strings are read;

A CSV-to-JSON converter, to which strings representing lines of a CSV file are written and from which corresponding JavaScript objects are read.

2.4. Pipe chains and backpressure

Streams are primarily used by piping them to each other. A readable stream can be piped directly to a writable stream, using its pipeTo() method, or it can be piped through one or more transform streams first, using its pipeThrough() method.

A set of streams piped together in this way is referred to as a pipe chain . In a pipe chain, the original source is the underlying source of the first readable stream in the chain; the ultimate sink is the underlying sink of the final writable stream in the chain.

Once a pipe chain is constructed, it will propagate signals regarding how fast chunks should flow through it. If any step in the chain cannot yet accept chunks, it propagates a signal backwards through the pipe chain, until eventually the original source is told to stop producing chunks so fast. This process of normalizing flow from the original source according to how fast the chain can process chunks is called backpressure .

Concretely, the original source is given the controller.desiredSize (or byteController.desiredSize ) value, and can then adjust its rate of data flow accordingly. This value is derived from the writer.desiredSize corresponding to the ultimate sink, which gets updated as the ultimate sink finishes writing chunks. The pipeTo() method used to construct the chain automatically ensures this information propagates back through the pipe chain.

When teeing a readable stream, the backpressure signals from its two branches will aggregate, such that if neither branch is read from, a backpressure signal will be sent to the underlying source of the original stream.

Piping locks the readable and writable streams, preventing them from being manipulated for the duration of the pipe operation. This allows the implementation to perform important optimizations, such as directly shuttling data from the underlying source to the underlying sink while bypassing many of the intermediate queues.

2.5. Internal queues and queuing strategies

Both readable and writable streams maintain internal queues , which they use for similar purposes. In the case of a readable stream, the internal queue contains chunks that have been enqueued by the underlying source, but not yet read by the consumer. In the case of a writable stream, the internal queue contains chunks which have been written to the stream by the producer, but not yet processed and acknowledged by the underlying sink.

A queuing strategy is an object that determines how a stream should signal backpressure based on the state of its internal queue. The queuing strategy assigns a size to each chunk, and compares the total size of all chunks in the queue to a specified number, known as the high water mark . The resulting difference, high water mark minus total size, is used to determine the desired size to fill the stream’s queue .

For readable streams, an underlying source can use this desired size as a backpressure signal, slowing down chunk generation so as to try to keep the desired size above or at zero. For writable streams, a producer can behave similarly, avoiding writes that would cause the desired size to go negative.

Concretely, a queuing strategy for web developer–created streams is given by any JavaScript object with a highWaterMark property. For byte streams the highWaterMark always has units of bytes. For other streams the default unit is chunks, but a size() function can be included in the strategy object which returns the size for a given chunk. This permits the highWaterMark to be specified in arbitrary floating-point units.

A simple example of a queuing strategy would be one that assigns a size of one to each chunk, and has a high water mark of three. This would mean that up to three chunks could be enqueued in a readable stream, or three chunks written to a writable stream, before the streams are considered to be applying backpressure. In JavaScript, such a strategy could be written manually as { highWaterMark : 3 , size () { return 1 ; }} , or using the built-in CountQueuingStrategy class, as new CountQueuingStrategy ({ highWaterMark : 3 }) .

2.6. Locking

A readable stream reader , or simply reader, is an object that allows direct reading of chunks from a readable stream. Without a reader, a consumer can only perform high-level operations on the readable stream: canceling the stream, or piping the readable stream to a writable stream. A reader is acquired via the stream’s getReader() method.

A readable byte stream has the ability to vend two types of readers: default readers and BYOB readers . BYOB ("bring your own buffer") readers allow reading into a developer-supplied buffer, thus minimizing copies. A non-byte readable stream can only vend default readers. Default readers are instances of the ReadableStreamDefaultReader class, while BYOB readers are instances of ReadableStreamBYOBReader .

Similarly, a writable stream writer , or simply writer, is an object that allows direct writing of chunks to a writable stream. Without a writer, a producer can only perform the high-level operations of aborting the stream or piping a readable stream to the writable stream. Writers are represented by the WritableStreamDefaultWriter class.

Under the covers, these high-level operations actually use a reader or writer themselves.

A given readable or writable stream only has at most one reader or writer at a time. We say in this case the stream is locked , and that the reader or writer is active . This state can be determined using the readableStream.locked or writableStream.locked properties.

A reader or writer also has the capability to release its lock , which makes it no longer active, and allows further readers or writers to be acquired. This is done via the defaultReader.releaseLock() , byobReader.releaseLock() , or writer.releaseLock() method, as appropriate.

3. Conventions

This specification depends on the Infra Standard. [INFRA]

This specification uses the abstract operation concept from the JavaScript specification for its internal algorithms. This includes treating their return values as completion records, and the use of ! and ? prefixes for unwrapping those completion records. [ECMASCRIPT]

This specification also uses the internal slot concept and notation from the JavaScript specification. (Although, the internal slots are on Web IDL platform objects instead of on JavaScript objects.)

The reasons for the usage of these foreign JavaScript specification conventions are largely historical. We urge you to avoid following our example when writing your own web specifications.

In this specification, all numbers are represented as double-precision 64-bit IEEE 754 floating point values (like the JavaScript Number type or Web IDL unrestricted double type), and all arithmetic operations performed on them must be done in the standard way for such values. This is particularly important for the data structure described in § 8.1 Queue-with-sizes. [IEEE-754]

4. Readable streams

4.1. Using readable streams

readableStream . pipeTo ( writableStream ) . then (() => console . log ( "All data successfully written!" )) . catch ( e => console . error ( "Something went wrong!" , e )); The simplest way to consume a readable stream is to simply pipe it to a writable stream . This ensures that backpressure is respected, and any errors (either writing or reading) are propagated through the chain:

readableStream . pipeTo ( new WritableStream ({ write ( chunk ) { console . log ( "Chunk received" , chunk ); }, close () { console . log ( "All data successfully read!" ); }, abort ( e ) { console . error ( "Something went wrong!" , e ); } })); If you simply want to be alerted of each new chunk from a readable stream, you can pipe it to a new writable stream that you custom-create for that purpose: By returning promises from your write() implementation, you can signal backpressure to the readable stream.

read() method to get successive chunks. For example, this code logs the next const reader = readableStream . getReader (); reader . read (). then ( ({ value , done }) => { if ( done ) { console . log ( "The stream was already closed!" ); } else { console . log ( value ); } }, e => console . error ( "The stream became errored and cannot be read from!" , e ) ); Although readable streams will usually be used by piping them to a writable stream, you can also read them directly by acquiring a reader and using itsmethod to get successive chunks. For example, this code logs the next chunk in the stream, if available: This more manual method of reading a stream is mainly useful for library authors building new high-level operations on streams, beyond the provided ones of piping and teeing.

const reader = readableStream . getReader ({ mode : "byob" }); let startingAB = new ArrayBuffer ( 1024 ); readInto ( startingAB ) . then ( buffer => console . log ( "The first 1024 bytes:" , buffer )) . catch ( e => console . error ( "Something went wrong!" , e )); function readInto ( buffer , offset = 0 ) { if ( offset === buffer . byteLength ) { return Promise . resolve ( buffer ); } const view = new Uint8Array ( buffer , offset , buffer . byteLength - offset ); return reader . read ( view ). then ( newView => { return readInto ( newView . buffer , offset + newView . byteLength ); }); } The above example showed using the readable stream’s default reader . If the stream is a readable byte stream , you can also acquire a BYOB reader for it, which allows more precise control over buffer allocation in order to avoid copies. For example, this code reads the first 1024 bytes from the stream into a single memory buffer: An important thing to note here is that the final buffer value is different from the startingAB , but it (and all intermediate buffers) shares the same backing memory allocation. At each step, the buffer is transferred to a new ArrayBuffer object. The newView is a new Uint8Array , with that ArrayBuffer object as its buffer property, the offset that bytes were written to as its byteOffset property, and the number of bytes that were written as its byteLength property.

4.2. ReadableStream class Theclass

✔ MDN ReadableStream In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) 14+ IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

The ReadableStream class is a concrete instance of the general readable stream concept. It is adaptable to any chunk type, and maintains an internal queue to keep track of data supplied by the underlying source but not yet read by any consumer.

4.2.1. Interface definition

The Web IDL definition for the ReadableStream class is given as follows:

[ Exposed =( Window , Worker , Worklet ), Transferable ] interface ReadableStream { constructor ( optional object underlyingSource , optional QueuingStrategy strategy = {}); readonly attribute boolean locked ; Promise < undefined > cancel ( optional any reason ); ReadableStreamReader getReader ( optional ReadableStreamGetReaderOptions options = {}); ReadableStream pipeThrough ( ReadableWritablePair transform , optional StreamPipeOptions options = {}); Promise < undefined > pipeTo ( WritableStream destination , optional StreamPipeOptions options = {}); sequence < ReadableStream > tee (); async iterable < any >( optional ReadableStreamIteratorOptions options = {}); }; typedef ( ReadableStreamDefaultReader or ReadableStreamBYOBReader ) ReadableStreamReader ; enum ReadableStreamReaderMode { "byob" }; dictionary ReadableStreamGetReaderOptions { ReadableStreamReaderMode mode ; }; dictionary ReadableStreamIteratorOptions { boolean preventCancel = false ; }; dictionary ReadableWritablePair { required ReadableStream readable ; required WritableStream writable ; }; dictionary StreamPipeOptions { boolean preventClose = false ; boolean preventAbort = false ; boolean preventCancel = false ; AbortSignal signal ; };

4.2.2. Internal slots

Instances of ReadableStream are created with the internal slots described in the following table:

Internal Slot Description (non-normative) [[controller]] A ReadableStreamDefaultController or ReadableByteStreamController created with the ability to control the state and queue of this stream [[Detached]] A boolean flag set to true when the stream is transferred [[disturbed]] A boolean flag set to true when the stream has been read from or canceled [[reader]] A ReadableStreamDefaultReader or ReadableStreamBYOBReader instance, if the stream is locked to a reader, or undefined if it is not [[state]] A string containing the stream’s current state, used internally; one of " readable ", " closed ", or " errored " [[storedError]] A value indicating how the stream failed, to be given as a failure reason or exception when trying to operate on an errored stream

4.2.3. The underlying source API

The ReadableStream() constructor accepts as its first argument a JavaScript object representing the underlying source. Such objects can contain any of the following properties:

The type of the controller argument passed to the start() and pull() methods depends on the value of the type option. If type is set to undefined (including via omission), then controller will be a ReadableStreamDefaultController . If it’s set to " bytes ", then controller will be a ReadableByteStreamController .

4.2.4. Constructor, methods, and properties

✔ MDN ReadableStream/ReadableStream In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) None IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

new ReadableStream( underlyingSource , strategy ) constructor steps are: If underlyingSource is missing, set it to null. Let underlyingSourceDict be underlyingSource , converted to an IDL value of type UnderlyingSource . We cannot declare the underlyingSource argument as having the UnderlyingSource type directly, because doing so would lose the reference to the original object. We need to retain the object so we can invoke the various methods on it. Perform ! InitializeReadableStream(this). If underlyingSourceDict [" type "] is " bytes ": If strategy [" size "] exists, throw a RangeError exception. Let highWaterMark be ? ( strategy , 0). Perform ? SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource , underlyingSourceDict , highWaterMark ). Otherwise, Assert: underlyingSourceDict [" type "] does not exist. Let sizeAlgorithm be ! ExtractSizeAlgorithm( strategy ). Let highWaterMark be ? ( strategy , 1). Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource , underlyingSourceDict , highWaterMark , sizeAlgorithm ). Theconstructor steps are:

✔ MDN ReadableStream/locked In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) 14+ IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

locked getter steps are: Return ! IsReadableStreamLocked(this). Thegetter steps are:

✔ MDN ReadableStream/cancel In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) 14+ IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

✔ MDN ReadableStream/getReader In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) 14+ IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

getReader( options ) method steps are: If options [" mode "] does not exist, return ? AcquireReadableStreamDefaultReader(this). Assert: options [" mode "] is " byob ". Return ? AcquireReadableStreamBYOBReader(this). function readAllChunks ( readableStream ) { const reader = readableStream . getReader (); const chunks = []; return pump (); function pump () { return reader . read (). then (({ value , done }) => { if ( done ) { return chunks ; } chunks . push ( value ); return pump (); }); } } An example of an abstraction that might benefit from using a reader is a function like the following, which is designed to read an entire readable stream into memory as an array of chunks Note how the first thing it does is obtain a reader, and from then on it uses the reader exclusively. This ensures that no other consumer can interfere with the stream, either by reading chunks or by canceling the stream. Themethod steps are:

MDN ReadableStream/pipeThrough Firefox None Safari 10.1+ Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) None IE None Firefox for Android None iOS Safari 10.3+ Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

pipeThrough( transform , options ) method steps are: If ! IsReadableStreamLocked(this) is true, throw a TypeError exception. If ! IsWritableStreamLocked( transform [" writable "]) is true, throw a TypeError exception. Let signal be options [" signal "] if it exists, or undefined otherwise. Let promise be ! ReadableStreamPipeTo(this, transform [" writable "], options [" preventClose "], options [" preventAbort "], options [" preventCancel "], signal ). Set promise .[[PromiseIsHandled]] to true. Return transform [" readable "]. pipeThrough(transform, options) would look like httpResponseBody . pipeThrough ( decompressorTransform ) . pipeThrough ( ignoreNonImageFilesTransform ) . pipeTo ( mediaGallery ); A typical example of constructing pipe chain usingwould look like Themethod steps are:

MDN ReadableStream/pipeTo Firefox None Safari 10.1+ Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) None IE None Firefox for Android None iOS Safari 10.3+ Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

✔ MDN ReadableStream/tee In all current engines. Firefox 65+ Safari 10.1+ Chrome 43+ Opera 30+ Edge 79+ Edge (Legacy) None IE None Firefox for Android 65+ iOS Safari 10.3+ Chrome for Android 43+ Android WebView 43+ Samsung Internet 4.0+ Opera Mobile 30+

tee() method steps are: Return ? ReadableStreamTee(this, false). cacheEntry representing an on-disk file, and another writable stream httpRequestBody representing an upload to a remote server, you could pipe the same readable stream to both destinations at once: const [ forLocal , forRemote ] = readableStream . tee (); Promise . all ([ forLocal . pipeTo ( cacheEntry ), forRemote . pipeTo ( httpRequestBody ) ]) . then (() => console . log ( "Saved the stream to the cache and also uploaded it!" )) . catch ( e => console . error ( "Either caching or uploading failed: " , e )); Teeing a stream is most useful when you wish to let two independent consumers read from the stream in parallel, perhaps even at different speeds. For example, given a writable streamrepresenting an on-disk file, and another writable streamrepresenting an upload to a remote server, you could pipe the same readable stream to both destinations at once: Themethod steps are:

4.2.5. Asynchronous iteration

for await (const chunk of stream ) { ... } for await (const chunk of stream .values({ preventCancel : true })) { ... } Asynchronously iterates over the chunks in the stream’s internal queue. Asynchronously iterating over the stream will lock it, preventing any other consumer from acquiring a reader. The lock will be released if the async iterator’s return() method is called, e.g. by break ing out of the loop. By default, calling the async iterator’s return() method will also cancel the stream. To prevent this, use the stream’s values() method, passing true for the preventCancel option.

ReadableStream , given stream , iterator , and args , are: Let reader be ? AcquireReadableStreamDefaultReader( stream ). Set iterator ’s reader to reader . Let preventCancel be args [0][" preventCancel "]. Set iterator ’s prevent cancel to preventCancel . The asynchronous iterator initialization steps for a, given, and, are:

4.2.6. Transfer via postMessage()

destination.postMessage(rs, { transfer: [rs] }); Sends a ReadableStream to another frame, window, or worker. The transferred stream can be used exactly like the original. The original will become locked and no longer directly usable.

dataHolder and value , are: Let deserializedRecord be ! StructuredDeserializeWithTransfer( dataHolder .[[port]], the current Realm). Let port be deserializedRecord .[[Deserialized]]. Perform ! SetUpCrossRealmTransformReadable( value , port ). Their transfer-receiving steps , givenand, are:

4.3. ReadableStreamGenericReader mixin Themixin

The ReadableStreamGenericReader mixin defines common internal slots, getters and methods that are shared between ReadableStreamDefaultReader and ReadableStreamBYOBReader objects.

4.3.1. Mixin definition

The Web IDL definition for the ReadableStreamGenericReader mixin is given as follows:

interface mixin ReadableStreamGenericReader { readonly attribute Promise < undefined > closed ; Promise < undefined > cancel ( optional any reason ); };

4.3.2. Internal slots

Instances of classes including the ReadableStreamGenericReader mixin are created with the internal slots described in the following table:

Internal Slot Description (non-normative) [[closedPromise]] A promise returned by the reader’s closed getter [[stream]] A ReadableStream instance that owns this reader

4.3.3. Methods and properties

⚠ MDN ReadableStreamBYOBReader/closed In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None ReadableStreamDefaultReader/closed In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

closed getter steps are: Return this.[[closedPromise]]. Thegetter steps are:

⚠ MDN ReadableStreamBYOBReader/cancel In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None ReadableStreamDefaultReader/cancel In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

4.4. ReadableStreamDefaultReader class Theclass

MDN ReadableStreamDefaultReader Firefox 65+ Safari ? Chrome 52+ Opera 39+ Edge 79+ Edge (Legacy) None IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android 52+ Android WebView 52+ Samsung Internet 6.0+ Opera Mobile 41+

The ReadableStreamDefaultReader class represents a default reader designed to be vended by a ReadableStream instance.

4.4.1. Interface definition

The Web IDL definition for the ReadableStreamDefaultReader class is given as follows:

[ Exposed =( Window , Worker , Worklet )] interface ReadableStreamDefaultReader { constructor ( ReadableStream stream ); Promise < ReadableStreamDefaultReadResult > read (); undefined releaseLock (); }; ReadableStreamDefaultReader includes ReadableStreamGenericReader ; dictionary ReadableStreamDefaultReadResult { any value ; boolean done ; };

4.4.2. Internal slots

Instances of ReadableStreamDefaultReader are created with the internal slots defined by ReadableStreamGenericReader , and those described in the following table:

Internal Slot Description (non-normative) [[readRequests]] A list of read requests, used when a consumer requests chunks sooner than they are available

A read request is a struct containing three algorithms to perform in reaction to filling the readable stream's internal queue or changing its state. It has the following items:

chunk steps An algorithm taking a chunk, called when a chunk is available for reading close steps An algorithm taking no arguments, called when no chunks are available because the stream is closed error steps An algorithm taking a JavaScript value, called when no chunks are available because the stream is errored

4.4.3. Constructor, methods, and properties

reader = new ReadableStreamDefaultReader ( stream ) This is equivalent to calling stream . getReader() . await reader . closed Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or the reader’s lock is released before the stream finishes closing. await reader . cancel ([ reason ]) If the reader is active, behaves the same as stream . cancel ( reason ) . { value , done } = await reader . read () Returns a promise that allows access to the next chunk from the stream’s internal queue, if available. If the chunk does become available, the promise will be fulfilled with an object of the form { value : theChunk , done : false } .

. If the stream becomes closed, the promise will be fulfilled with an object of the form { value : undefined , done : true } .

. If the stream becomes errored, the promise will be rejected with the relevant error. If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. reader . releaseLock () Releases the reader’s lock on the corresponding stream. After the lock is released, the reader is no longer active. If the associated stream is errored when the lock is released, the reader will appear errored in the same way from now on; otherwise, the reader will appear closed. A reader’s lock cannot be released while it still has a pending read request, i.e., if a promise returned by the reader’s read() method has not yet been settled. Attempting to do so will throw a TypeError and leave the reader locked to the stream.

⚠ MDN ReadableStreamDefaultReader/ReadableStreamDefaultReader In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

new ReadableStreamDefaultReader( stream ) constructor steps are: Perform ? SetUpReadableStreamDefaultReader(this, stream ). Theconstructor steps are:

⚠ MDN ReadableStreamDefaultReader/read In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

⚠ MDN ReadableStreamDefaultReader/releaseLock In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ? WritableStreamDefaultWriter/releaseLock In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

releaseLock() method steps are: If this.[[stream]] is undefined, return. If this.[[readRequests]] is not empty, throw a TypeError exception. Perform ! ReadableStreamReaderGenericRelease(this). Themethod steps are:

4.5. ReadableStreamBYOBReader class Theclass

⚠ MDN ReadableStreamBYOBReader In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

The ReadableStreamBYOBReader class represents a BYOB reader designed to be vended by a ReadableStream instance.

4.5.1. Interface definition

The Web IDL definition for the ReadableStreamBYOBReader class is given as follows:

[ Exposed =( Window , Worker , Worklet )] interface ReadableStreamBYOBReader { constructor ( ReadableStream stream ); Promise < ReadableStreamBYOBReadResult > read ( ArrayBufferView view ); undefined releaseLock (); }; ReadableStreamBYOBReader includes ReadableStreamGenericReader ; dictionary ReadableStreamBYOBReadResult { ArrayBufferView value ; boolean done ; };

4.5.2. Internal slots

Instances of ReadableStreamBYOBReader are created with the internal slots defined by ReadableStreamGenericReader , and those described in the following table:

Internal Slot Description (non-normative) [[readIntoRequests]] A list of read-into requests, used when a consumer requests chunks sooner than they are available

A read-into request is a struct containing three algorithms to perform in reaction to filling the readable byte stream's internal queue or changing its state. It has the following items:

chunk steps An algorithm taking a chunk, called when a chunk is available for reading close steps An algorithm taking a chunk, called when no chunks are available because the stream is closed error steps An algorithm taking a JavaScript value, called when no chunks are available because the stream is errored

The close steps take a chunk so that it can return the backing memory to the caller if possible. For example, byobReader.read(chunk) will fulfill with { value : newViewOnSameMemory , done : true } for closed streams, instead of the more traditional { value : undefined , done : true } .

4.5.3. Constructor, methods, and properties

reader = new ReadableStreamBYOBReader ( stream ) This is equivalent to calling stream . getReader ({ mode : " byob " }) . await reader . closed Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or the reader’s lock is released before the stream finishes closing. await reader . cancel ([ reason ]) If the reader is active, behaves the same stream . cancel ( reason ) . { value , done } = await reader . read ( view ) Attempts to reads bytes into view , and returns a promise resolved with the result: If the chunk does become available, the promise will be fulfilled with an object of the form { value : theChunk , done : false } . In this case, view will be detached and no longer usable, but theChunk will be a new view (of the same type) onto the same backing memory region, with the chunk’s data written into it.

. In this case, will be detached and no longer usable, but will be a new view (of the same type) onto the same backing memory region, with the chunk’s data written into it. If the stream becomes closed, the promise will be fulfilled with an object of the form { value : theChunk , done : true } . In this case, view will be detached and no longer usable, but theChunk will be a new view (of the same type) onto the same backing memory region, with no modifications, to ensure the memory is returned to the caller.

. In this case, will be detached and no longer usable, but will be a new view (of the same type) onto the same backing memory region, with no modifications, to ensure the memory is returned to the caller. If the stream becomes errored, the promise will be rejected with the relevant error. If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. reader . releaseLock () Releases the reader’s lock on the corresponding stream. After the lock is released, the reader is no longer active. If the associated stream is errored when the lock is released, the reader will appear errored in the same way from now on; otherwise, the reader will appear closed. A reader’s lock cannot be released while it still has a pending read request, i.e., if a promise returned by the reader’s read() method has not yet been settled. Attempting to do so will throw a TypeError and leave the reader locked to the stream.

⚠ MDN ReadableStreamBYOBReader/ReadableStreamBYOBReader In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

new ReadableStreamBYOBReader( stream ) constructor steps are: Perform ? SetUpReadableStreamBYOBReader(this, stream ). Theconstructor steps are:

⚠ MDN ReadableStreamBYOBReader/read In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

⚠ MDN ReadableStreamBYOBReader/releaseLock In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

releaseLock() method steps are: If this.[[stream]] is undefined, return. If this.[[readIntoRequests]] is not empty, throw a TypeError exception. Perform ! ReadableStreamReaderGenericRelease(this). Themethod steps are:

4.6. ReadableStreamDefaultController class Theclass

MDN ReadableStreamDefaultController Firefox 65+ Safari ? Chrome 52+ Opera 39+ Edge 79+ Edge (Legacy) None IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android 52+ Android WebView 52+ Samsung Internet 6.0+ Opera Mobile 41+

The ReadableStreamDefaultController class has methods that allow control of a ReadableStream 's state and internal queue. When constructing a ReadableStream that is not a readable byte stream, the underlying source is given a corresponding ReadableStreamDefaultController instance to manipulate.

4.6.1. Interface definition

The Web IDL definition for the ReadableStreamDefaultController class is given as follows:

[ Exposed =( Window , Worker , Worklet )] interface ReadableStreamDefaultController { readonly attribute unrestricted double ? desiredSize ; undefined close (); undefined enqueue ( optional any chunk ); undefined error ( optional any e ); };

4.6.2. Internal slots

Instances of ReadableStreamDefaultController are created with the internal slots described in the following table:

4.6.3. Methods and properties

⚠ MDN ReadableStreamDefaultController/desiredSize In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

desiredSize getter steps are: Return ! ReadableStreamDefaultControllerGetDesiredSize(this). Thegetter steps are:

⚠ MDN ReadableStreamDefaultController/close In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

close() method steps are: If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception. Perform ! ReadableStreamDefaultControllerClose(this). Themethod steps are:

⚠ MDN ReadableStreamDefaultController/enqueue In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

enqueue( chunk ) method steps are: If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception. Perform ? ReadableStreamDefaultControllerEnqueue(this, chunk ). Themethod steps are:

⚠ MDN ReadableStreamDefaultController/error In only one current engine. Firefox 65+ Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) ? IE ? Firefox for Android 65+ iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

error( e ) method steps are: Perform ! ReadableStreamDefaultControllerError(this, e ). Themethod steps are:

4.6.4. Internal methods

The following are internal methods implemented by each ReadableStreamDefaultController instance. The readable stream implementation will polymorphically call to either these, or to their counterparts for BYOB controllers, as discussed in § 4.9.2 Interfacing with controllers.

[[CancelSteps]]( reason ) implements the Perform ! ResetQueue(this). Let result be the result of performing this.[[cancelAlgorithm]], passing reason . Perform ! ReadableStreamDefaultControllerClearAlgorithms(this). Return result . implements the [[CancelSteps]] contract. It performs the following steps:

4.7. ReadableByteStreamController class Theclass

⚠ MDN ReadableByteStreamController In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

The ReadableByteStreamController class has methods that allow control of a ReadableStream 's state and internal queue. When constructing a ReadableStream that is a readable byte stream, the underlying source is given a corresponding ReadableByteStreamController instance to manipulate.

4.7.1. Interface definition

The Web IDL definition for the ReadableByteStreamController class is given as follows:

4.7.2. Internal slots

Instances of ReadableByteStreamController are created with the internal slots described in the following table:

Although ReadableByteStreamController instances have [[queue]] and [[queueTotalSize]] slots, we do not use most of the abstract operations in § 8.1 Queue-with-sizes on them, as the way in which we manipulate this queue is rather different than the others in the spec. Instead, we update the two slots together manually. This might be cleaned up in a future spec refactoring.

A readable byte stream queue entry is a struct encapsulating the important aspects of a chunk for the specific case of readable byte streams. It has the following items:

buffer An ArrayBuffer , which will be a transferred version of the one originally supplied by the underlying byte source byte offset A nonnegative integer number giving the byte offset derived from the view originally supplied by the underlying byte source byte length A nonnegative integer number giving the byte length derived from the view originally supplied by the underlying byte source

A pull-into descriptor is a struct used to represent pending BYOB pull requests. It has the following items:

buffer An ArrayBuffer byte offset A nonnegative integer byte offset into the buffer where the underlying byte source will start writing byte length A nonnegative integer number of bytes which can be written into the buffer bytes filled A nonnegative integer number of bytes that have been written into the buffer so far element size A positive integer representing the number of bytes that can be written into the buffer at a time, using views of the type described by the view constructor view constructor A typed array constructor or %DataView% , which will be used for constructing a view with which to write into the buffer reader type Either " default " or " byob ", indicating what type of readable stream reader initiated this request

4.7.3. Methods and properties

⚠ MDN ReadableByteStreamController/byobRequest In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

⚠ MDN ReadableByteStreamController/desiredSize In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

desiredSize getter steps are: Return ! ReadableByteStreamControllerGetDesiredSize(this). Thegetter steps are:

⚠ MDN ReadableByteStreamController/close In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

close() method steps are: If this.[[closeRequested]] is true, throw a TypeError exception. If this.[[stream]].[[state]] is not " readable ", throw a TypeError exception. Perform ? ReadableByteStreamControllerClose(this). Themethod steps are:

⚠ MDN ReadableByteStreamController/enqueue In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

enqueue( chunk ) method steps are: If chunk .[[ByteLength]] is 0, throw a TypeError exception. If chunk .[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a TypeError exception. If this.[[closeRequested]] is true, throw a TypeError exception. If this.[[stream]].[[state]] is not " readable ", throw a TypeError exception. Return ! ReadableByteStreamControllerEnqueue(this, chunk ). Themethod steps are:

⚠ MDN ReadableByteStreamController/error In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

error( e ) method steps are: Perform ! ReadableByteStreamControllerError(this, e ). Themethod steps are:

4.7.4. Internal methods

The following are internal methods implemented by each ReadableByteStreamController instance. The readable stream implementation will polymorphically call to either these, or to their counterparts for default controllers, as discussed in § 4.9.2 Interfacing with controllers.

[[CancelSteps]]( reason ) implements the If this.[[pendingPullIntos]] is not empty, Let firstDescriptor be this.[[pendingPullIntos]][0]. Set firstDescriptor ’s bytes filled to 0. Perform ! ResetQueue(this). Let result be the result of performing this.[[cancelAlgorithm]], passing in reason . Perform ! ReadableByteStreamControllerClearAlgorithms(this). Return result . implements the [[CancelSteps]] contract. It performs the following steps:

4.8. ReadableStreamBYOBRequest class Theclass

⚠ MDN ReadableStreamBYOBRequest In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

The ReadableStreamBYOBRequest class represents a pull-into request in a ReadableByteStreamController .

4.8.1. Interface definition

The Web IDL definition for the ReadableStreamBYOBRequest class is given as follows:

4.8.2. Internal slots

Instances of ReadableStreamBYOBRequest are created with the internal slots described in the following table:

Internal Slot Description (non-normative) [[controller]] The parent ReadableByteStreamController instance [[view]] A typed array representing the destination region to which the controller can write generated data, or null after the BYOB request has been invalidated.

4.8.3. Methods and properties

⚠ MDN ReadableStreamBYOBRequest/view In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

view getter steps are: Return this.[[view]]. Thegetter steps are:

⚠ MDN ReadableStreamBYOBRequest/respond In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

respond( bytesWritten ) method steps are: If this.[[controller]] is undefined, throw a TypeError exception. If IsDetachedBuffer(this.[[view]].[[ArrayBuffer]]) is true, throw a TypeError exception. Assert: this.[[view]].[[ByteLength]] > 0. Assert: this.[[view]].[[ViewedArrayBuffer]].[[ByteLength]] > 0. Perform ? ReadableByteStreamControllerRespond(this.[[controller]], bytesWritten ). Themethod steps are:

⚠ MDN ReadableStreamBYOBRequest/respondWithNewView In no current engines. Firefox None Safari None Chrome None Opera None Edge None Edge (Legacy) None IE None Firefox for Android None iOS Safari None Chrome for Android None Android WebView None Samsung Internet None Opera Mobile None

respondWithNewView( view ) method steps are: If view .[[ByteLength]] is 0, throw a TypeError exception. If view .[[ViewedArrayBuffer]].[[ArrayBufferByteLength]] is 0, throw a TypeError exception. If this.[[controller]] is undefined, throw a TypeError exception. Return ? ReadableByteStreamControllerRespondWithNewView(this.[[controller]], view ). Themethod steps are:

4.9. Abstract operations

4.9.1. Working with readable streams

The following abstract operations operate on ReadableStream instances at a higher level.

AcquireReadableStreamBYOBReader( stream ) performs the following steps: Let reader be a new ReadableStreamBYOBReader . Perform ? SetUpReadableStreamBYOBReader( reader , stream ). Return reader . performs the following steps:

AcquireReadableStreamDefaultReader( stream ) performs the following steps: Let reader be a new ReadableStreamDefaultReader . Perform ? SetUpReadableStreamDefaultReader( reader , stream ). Return reader . performs the following steps:

CreateReadableStream( startAlgorithm , pullAlgorithm , cancelAlgorithm [, highWaterMark , [, sizeAlgorithm ]]) performs the following steps: If highWaterMark was not passed, set it to 1. If sizeAlgorithm was not passed, set it to an algorithm that returns 1. Assert: ! IsNonNegativeNumber( highWaterMark ) is true. Let stream be a new ReadableStream . Perform ! InitializeReadableStream( stream ). Let controller be a new ReadableStreamDefaultController . Perform ? SetUpReadableStreamDefaultController( stream , controller , startAlgorithm , pullAlgorithm , cancelAlgorithm , highWaterMark , sizeAlgorithm ). Return stream . performs the following steps: This abstract operation will throw an exception if and only if the supplied startAlgorithm throws.

InitializeReadableStream( stream ) performs the following steps: Set stream .[[state]] to " readable ". Set stream .[[reader]] and stream .[[storedError]] to undefined. Set stream .[[disturbed]] to false. performs the following steps:

IsReadableStreamLocked( stream ) performs the following steps: If stream .[[reader]] is undefined, return false. Return true. performs the following steps:

Various abstract operations performed here include object creation (often of promises), which usually would require specifying a realm for the created object. However, because of the locking, none of these objects can be observed by author code. As such, the realm used to create them does not matter.

4.9.2. Interfacing with controllers

In terms of specification factoring, the way that the ReadableStream class encapsulates the behavior of both simple readable streams and readable byte streams into a single class is by centralizing most of the potentially-varying logic inside the two controller classes, ReadableStreamDefaultController and ReadableByteStreamController . Those classes define most of the stateful internal slots and abstract operations for how a stream’s internal queue is managed and how it interfaces with its underlying source or underlying byte source.

Each controller class defines two internal methods, which are called by the ReadableStream algorithms:

[[CancelSteps]]( reason ) The controller’s steps that run in reaction to the stream being canceled, used to clean up the state stored in the controller and inform the underlying source. [[PullSteps]]( readRequest ) The controller’s steps that run when a default reader is read from, used to pull from the controller any queued chunks, or pull from the underlying source to get more chunks.

(These are defined as internal methods, instead of as abstract operations, so that they can be called polymorphically by the ReadableStream algorithms, without having to branch on which type of controller is present.)

The rest of this section concerns abstract operations that go in the other direction: they are used by the controller implementations to affect their associated ReadableStream object. This translates internal state changes of the controller into developer-facing results visible through the ReadableStream 's public API.

ReadableStreamAddReadIntoRequest( stream , readRequest ) performs the following steps: Assert: stream .[[reader]] implements ReadableStreamBYOBReader . Assert: stream .[[state]] is " readable " or " closed ". Append readRequest to stream .[[reader]].[[readIntoRequests]]. performs the following steps:

ReadableStreamAddReadRequest( stream , readRequest performs the following steps: Assert: stream .[[reader]] implements ReadableStreamDefaultReader . Assert: stream .[[state]] is " readable ". Append readRequest to stream .[[reader]].[[readRequests]]. performs the following steps:

ReadableStreamClose( stream ) performs the following steps: Assert: stream .[[state]] is " readable ". Set stream .[[state]] to " closed ". Let reader be stream .[[reader]]. If reader is undefined, return. If reader implements ReadableStreamDefaultReader , For each readRequest of reader .[[readRequests]], Perform readRequest ’s close steps. Set reader .[[readRequests]] to an empty list. Resolve reader .[[closedPromise]] with undefined. performs the following steps:

ReadableStreamFulfillReadIntoRequest( stream , chunk , done ) performs the following steps: Let reader be stream .[[reader]]. Assert: reader .[[readIntoRequests]] is not empty. Let readIntoRequest be reader .[[readIntoRequests]][0]. Remove readIntoRequest from reader .[[readIntoRequests]]. If done is true, perform readIntoRequest ’s close steps, given chunk . Otherwise, perform readIntoRequest ’s chunk steps, given chunk . performs the following steps:

ReadableStreamFulfillReadRequest( stream , chunk , done ) performs the following steps: Let reader be stream .[[reader]]. Assert: reader .[[readRequests]] is not empty. Let readRequest be reader .[[readRequests]][0]. Remove readRequest from reader .[[readRequests]]. If done is true, perform readRequest ’s close steps. Otherwise, perform readRequest ’s chunk steps, given chunk . performs the following steps:

ReadableStreamGetNumReadIntoRequests( stream ) performs the following steps: Return stream .[[reader]].[[readIntoRequests]]'s size. performs the following steps:

ReadableStreamGetNumReadRequests( stream ) performs the following steps: Return stream .[[reader]].[[readRequests]]'s size. performs the following steps:

ReadableStreamHasBYOBReader( stream ) performs the following steps: Let reader be stream .[[reader]]. If reader is undefined, return false. If reader implements ReadableStreamBYOBReader , return true. Return false. performs the following steps:

ReadableStreamHasDefaultReader( stream ) performs the following steps: Let reader be stream .[[reader]]. If reader is undefined, return false. If reader implements ReadableStreamDefaultReader , return true. Return false. performs the following steps:

4.9.3. Readers

The following abstract operations support the implementation and manipulation of ReadableStreamDefaultReader and ReadableStreamBYOBReader instances.

ReadableStreamReaderGenericCancel( reader , reason ) performs the following steps: Let stream be reader .[[stream]]. Assert: stream is not undefined. Return ! ReadableStreamCancel( stream , reason ). performs the following steps:

ReadableStreamBYOBReaderRead( reader , view , readIntoRequest ) performs the following steps: Let stream be reader .[[stream]]. Assert: stream is not undefined. Set stream .[[disturbed]] to true. If stream .[[state]] is " errored ", perform readIntoRequest ’s error steps given stream .[[storedError]]. Return ! ReadableByteStreamControllerPullInto( stream .[[controller]], view , readIntoRequest ). performs the following steps:

ReadableStreamDefaultReaderRead( reader , readRequest ) performs the following steps: Let stream be reader .[[stream]]. Assert: stream is not undefined. Set stream .[[disturbed]] to true. If stream .[[state]] is " closed ", perform readRequest ’s close steps. Otherwise, if stream .[[state]] is " errored ", perform readRequest ’s error steps given stream .[[storedError]]. Otherwise, Assert: stream .[[state]] is " readable ". Perform ! stream .[[controller]].[[PullSteps]]( readRequest ). performs the following steps:

SetUpReadableStreamBYOBReader( reader , stream ) performs the following steps: If ! IsReadableStreamLocked( stream ) is true, throw a TypeError exception. If stream .[[controller]] does not implement ReadableByteStreamController , throw a TypeError exception. Perform ! ReadableStreamReaderGenericInitialize( reader , stream ). Set reader .[[readIntoRequests]] to a new empty list. performs the following steps:

SetUpReadableStreamDefaultReader( reader , stream ) performs the following steps: If ! IsReadableStreamLocked( stream ) is true, throw a TypeError exception. Perform ! ReadableStreamReaderGenericInitialize( reader , stream ). Set reader .[[readRequests]] to a new empty list. performs the following steps:

4.9.4. Default controllers

The following abstract operations support the implementation of the ReadableStreamDefaultController class.

ReadableStreamDefaultControllerCallPullIfNeeded( controller ) performs the following steps: Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull( controller ). If shouldPull is false, return. If controller .[[pulling]] is true, Set controller .[[pullAgain]] to true. Return. Assert: controller .[[pullAgain]] is false. Set controller .[[pulling]] to true. Let pullPromise be the result of performing controller .[[pullAlgorithm]]. Upon fulfillment of pullPromise , Set controller .[[pulling]] to false. If controller .[[pullAgain]] is true, Set controller .[[pullAgain]] to false. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded( controller ). Upon rejection of pullPromise with reason e , Perform ! ReadableStreamDefaultControllerError( controller , e ). performs the following steps:

ReadableStreamDefaultControllerShouldCallPull( controller ) performs the following steps: Let stream be controller .[[stream]]. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue( controller ) is false, return false. If controller .[[started]] is false, return false. If ! IsReadableStreamLocked( stream ) is true and ! ReadableStreamGetNumReadRequests( stream ) > 0, return true. Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize( controller ). Assert: desiredSize is not null. If desiredSize > 0, return true. Return false. performs the following steps:

ReadableStreamDefaultControllerClearAlgorithms( controller ) is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the ReadableStream itself is still referenced. is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the underlying source object to be garbage collected even if theitself is still referenced. This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail. It performs the following steps: Set controller .[[pullAlgorithm]] to undefined. Set controller .[[cancelAlgorithm]] to undefined. Set controller .[[strategySizeAlgorithm]] to undefined.

ReadableStreamDefaultControllerClose( controller ) performs the following steps: If ! ReadableStreamDefaultControllerCanCloseOrEnqueue( controller ) is false, return. Let stream be controller .[[stream]]. Set controller .[[closeRequested]] to true. If controller .[[queue]] is empty, Perform ! ReadableStreamDefaultControllerClearAlgorithms( controller ). Perform ! ReadableStreamClose( stream ). performs the following steps:

ReadableStreamDefaultControllerEnqueue( controller , chunk ) performs the following steps: If ! ReadableStreamDefaultControllerCanCloseOrEnqueue( controller ) is false, return. Let stream be controller .[[stream]]. If ! IsReadableStreamLocked( stream ) is true and ! ReadableStreamGetNumReadRequests( stream ) > 0, perform ! ReadableStreamFulfillReadRequest( stream , chunk , false). Otherwise, Let result be the result of performing controller .[[strategySizeAlgorithm]], passing in chunk , and interpreting the result as a completion record. If result is an abrupt completion, Perform ! ReadableStreamDefaultControllerError( controller , result .[[Value]]). Return result . Let chunkSize be result .[[Value]]. Let enqueueResult be EnqueueValueWithSize( controller , chunk , chunkSize ). If enqueueResult is an abrupt completion, Perform ! ReadableStreamDefaultControllerError( controller , enqueueResult .[[Value]]). Return enqueueResult . Perform ! ReadableStreamDefaultControllerCallPullIfNeeded( controller ). performs the following steps:

ReadableStreamDefaultControllerError( controller , e ) performs the following steps: Let stream be controller .[[stream]]. If stream .[[state]] is not " readable ", return. Perform ! ResetQueue( controller ). Perform ! ReadableStreamDefaultControllerClearAlgorithms( controller ). Perform ! ReadableStreamError( stream , e ). performs the following steps:

ReadableStreamDefaultControllerGetDesiredSize( controller ) performs the following steps: Let state be controller .[[stream]].[[state]]. If state is " errored ", return null. If state is " closed ", return 0. Return controller .[[strategyHWM]] − controller .[[queueTotalSize]]. performs the following steps:

ReadableStreamDefaultControllerHasBackpressure( controller ) is used in the implementation of TransformStream . It performs the following steps: If ! ReadableStreamDefaultControllerShouldCallPull( controller ) is true, return false. Otherwise, return true. is used in the implementation of. It performs the following steps:

ReadableStreamDefaultControllerCanCloseOrEnqueue( controller ) performs the following steps: Let state be controller .[[stream]].[[state]]. If controller .[[closeRequested]] is false and state is " readable ", return true. Otherwise, return false. performs the following steps: The case where controller .[[closeRequested]] is false, but state is not " readable ", happens when the stream is errored via controller.error() , or when it is closed without its controller’s controller.close() method ever being called: e.g., if the stream was closed by a call to stream.cancel() .

4.9.5. Byte stream controllers

ReadableByteStreamControllerCallPullIfNeeded( controller ) performs the following steps: Let shouldPull be ! ReadableByteStreamControllerShouldCallPull( controller ). If shouldPull is false, return. If controller .[[pulling]] is true, Set controller .[[pullAgain]] to true. Return. Assert: controller .[[pullAgain]] is false. Set controller .[[pulling]] to true. Let pullPromise be the result of performing controller .[[pullAlgorithm]]. Upon fulfillment of pullPromise , Set controller .[[pulling]] to false. If controller .[[pullAgain]] is true, Set controller .[[pullAgain]] to false. Perform ! ReadableByteStreamControllerCallPullIfNeeded( controller ). Upon rejection of pullPromise with reason e , Perform ! ReadableByteStreamControllerError( controller , e ). performs the following steps:

ReadableByteStreamControllerClearAlgorithms( controller ) is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the ReadableStream itself is still referenced. is called once the stream is closed or errored and the algorithms will not be executed any more. By removing the algorithm references it permits the underlying byte source object to be garbage collected even if theitself is still referenced. This is observable using weak references. See tc39/proposal-weakrefs#31 for more detail. It performs the following steps: Set controller .[[pullAlgorithm]] to undefined. Set controller .[[cancelAlgorithm]] to undefined.

ReadableByteStreamControllerClearPendingPullIntos( controller ) performs the following steps: Perform ! ( controller ). Set controller .[[pendingPullIntos]] to a new empty list. performs the following steps:

ReadableByteStreamControllerClose( controller ) performs the following steps: Let stream be controller .[[stream]]. If controller .[[closeRequested]] is true or stream .[[state]] is not " readable ", return. If controller .[[queueTotalSize]] > 0, Set controller .[[closeRequested]] to true. Return. If controller .[[pendingPullIntos]] is not empty, Let firstPendingPullInto be controller .[[pendingPullIntos]][0]. If firstPendingPullInto ’s bytes filled > 0, Let e be a new TypeError exception. Perform ! ReadableByteStreamControllerError( controller , e ). Throw e . Perform ! ReadableByteStreamControllerClearAlgorithms( controller ). Perform ! ReadableStreamClose( stream ). performs the following steps:

ReadableByteStreamControllerCommitPullIntoDescriptor( stream , pullIntoDescriptor ) performs the following steps: Assert: stream .[[state]] is not " errored ". Let done be false. If stream .[[state]] is " closed ", Assert: pullIntoDescriptor ’s bytes filled is 0. Set done to true. Let filledView be ! ReadableByteStreamControllerConvertPullIntoDescriptor( pullIntoDescriptor ). If pullIntoDescriptor ’s reader type is " default ", Perform ! ReadableStreamFulfillReadRequest( stream , filledView , done ). Otherwise, Assert: pullIntoDescriptor ’s reader type is " byob ". Perform ! ReadableStreamFulfillReadIntoRequest( stream , filledView , done ). performs the following steps:

ReadableByteStreamControllerEnqueue( controller , chunk ) performs the following steps: Let stream be controller .[[stream]]. If controller .[[closeRequested]] is true or stream .[[state]] is not " readable ", return. Let buffer be chunk .[[ViewedArrayBuffer]]. Let byteOffset be chunk .[[ByteOffset]]. Let byteLength be chunk .[[ByteLength]]. Let transferredBuffer be ! TransferArrayBuffer( buffer ). If ! ReadableStreamHasDefaultReader( stream ) is true If ! ReadableStreamGetNumReadRequests( stream ) is 0, Perform ! ReadableByteStreamControllerEnqueueChunkToQueue( controller , transferredBuffer , byteOffset , byteLength ). Otherwise, Assert: controller .[[queue]] is empty. Let transferredView be ! Construct( %Uint8Array% , « transferredBuffer , byteOffset , byteLength »). Perform ! ReadableStreamFulfillReadRequest( stream , transferredView , false). Otherwise, if ! ReadableStreamHasBYOBReader( stream ) is true, Perform ! ReadableByteStreamControllerEnqueueChunkToQueue( controller , transferredBuffer , byteOffset , byteLength ). Perform ! ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( controller ). Otherwise, Assert: ! IsReadableStreamLocked( stream ) is false. Perform ! ReadableByteStreamControllerEnqueueChunkToQueue( controller , transferredBuffer , byteOffset , byteLength ). Perform ! ReadableByteStreamControllerCallPullIfNeeded( controller ). performs the following steps:

ReadableByteStreamControllerError( controller , e ) performs the following steps: Let stream be controller .[[stream]]. If stream .[[state]] is not " readable ", return. Perform ! ReadableByteStreamControllerClearPendingPullIntos( controller ). Perform ! ResetQueue( controller ). Perform ! ReadableByteStreamControllerClearAlgorithms( controller ). Perform ! ReadableStreamError( stream , e ). performs the following steps:

ReadableByteStreamControllerFillHeadPullIntoDescriptor( controller , size , pullIntoDescriptor ) performs the following steps: Assert: either controller .[[pendingPullIntos]] is empty, or controller .[[pendingPullIntos]][0] is pullIntoDescriptor . Perform ! ( controller ). Set pullIntoDescriptor ’s bytes filled to bytes filled + size . performs the following steps:

ReadableByteStreamControllerGetDesiredSize( controller ) performs the following steps: Let state be controller .[[stream]].[[state]]. If state is " errored ", return null. If state is " closed ", return 0. Return controller .[[strategyHWM]] − controller .[[queueTotalSize]]. performs the following steps:

ReadableByteStreamControllerHandleQueueDrain( controller ) performs the following steps: Assert: controller .[[stream]].[[state]] is " readable ". If controller .[[queueTotalSize]] is 0 and controller .[[closeRequested]] is true, Perform ! ReadableByteStreamControllerClearAlgorithms( controller ). Perform ! ReadableStreamClose( controller .[[stream]]). Otherwise, Perform ! ReadableByteStreamControllerCallPullIfNeeded( controller ). performs the following steps:

If controller .[[byobRequest]] is null, return. Set controller .[[byobRequest]].[[controller]] to undefined. Set controller .[[byobRequest]].[[view]] to null. Set controller .[[byobRequest]] to null. performs the following steps:

ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue( controller ) performs the following steps: Assert: controller .[[closeRequested]] is false. While controller .[[pendingPullIntos]] is not empty, If controller .[[queueTotalSize]] is 0, return. Let pullIntoDescriptor be controller .[[pendingPullIntos]][0]. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue( controller , pullIntoDescriptor ) is true, Perform ! ReadableByteStreamControllerShiftPendingPullInto( controller ). Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor( controller .[[stream]], pullIntoDescriptor ). performs the following steps:

ReadableByteStreamControllerRespond( controller , bytesWritten ) performs the following steps: Assert: controller .[[pendingPullIntos]] is not empty. Perform ? ReadableByteStreamControllerRespondInternal( controller , bytesWritten ). performs the following steps:

ReadableByteStreamControllerRespondInClosedState( controller , firstDescriptor ) performs the following steps: Set firstDescriptor ’s buffer to ! TransferArrayBuffer( firstDescriptor ’s buffer). Assert: firstDescriptor ’s bytes filled is 0. Let stream be controller .[[stream]]. If ! ReadableStreamHasBYOBReader( stream ) is true, While ! ReadableStreamGetNumReadIntoRequests( stream ) > 0, Let pullIntoDescriptor be ! ReadableByteStreamControllerShiftPendingPullInto( controller ). Perform ! ReadableByteStreamControllerCommitPullIntoDescriptor( stream , pullIntoDescriptor ). performs the following steps:

ReadableByteStreamControllerRespondInternal( controller , bytesWritten ) performs the following steps: Let firstDescriptor be controller .[[pendingPullIntos]][0]. Let state be controller .[[stream]].[[state]]. If state is " closed ", If bytesWritten is not 0, throw a TypeError exception. Perform ! ReadableByteStreamControllerRespondInClosedState( controller , firstDescriptor ). Otherwise, Assert: state is " readable ". Perform ? ReadableByteStreamControllerRespondInReadableState( controller , bytesWritten , firstDescriptor ). Perform ! ReadableByteStreamControllerCallPullIfNeeded( controller ). performs the following steps:

ReadableByteStreamControllerRespondWithNewView( controller , view ) performs the following steps: Assert: controller .[[pendingPullIntos]] is not empty. Let firstDescriptor be controller .[[pendingPullIntos]][0]. If firstDescriptor ’s byte offset + firstDescriptor ’ bytes filled is not view .[[ByteOffset]], throw a RangeError exception. If firstDescriptor ’s byte length is not view .[[ByteLength]], throw a RangeError exception. Set firstDescriptor ’s buffer to view .[[ViewedArrayBuffer]]. Perform ? ReadableByteStreamControllerRespondInternal( controller , view .[[ByteLength]]). performs the following steps:

ReadableByteStreamControllerShiftPendingPullInto( controller ) performs the following steps: Let descriptor be controller .[[pendingPullIntos]][0]. Remove descriptor from controller .[[pendingPullIntos]]. Perform ! ( controller ). Return descriptor . performs the following steps:

ReadableByteStreamControllerShouldCallPull( controller ) performs the following steps: Let stream be controller .[[stream]]. If stream .[[state]] is not " readable ", return false. If controller .[[closeRequested]] is true, return false. If controller .[[started]] is false, return false. If ! ReadableStreamHasDefaultReader( stream ) is true and ! ReadableStreamGetNumReadRequests( stream ) > 0, return true. If ! ReadableStreamHasBYOBReader( stream ) is true and ! ReadableStreamGetNumReadIntoRequests( stream ) > 0, return true. Let desiredSize be ! ReadableByteStreamControllerGetDesiredSize( controller ). Assert: desiredSize is not null. If desiredSize > 0, return true. Return false. performs the following steps:

5. Writable streams

5.1. Using writable streams

readableStream . pipeTo ( writableStream ) . then (() => console . log ( "All data successfully written!" )) . catch ( e => console . error ( "Something went wrong!" , e )); The usual way to write to a writable stream is to simply pipe readable stream to it. This ensures that backpressure is respected, so that if the writable stream’s underlying sink is not able to accept data as fast as the readable stream can produce it, the readable stream is informed of this and has a chance to slow down its data production.

write() and close() methods. Since writable streams queue any incoming writes, and take care internally to forward them to the function writeArrayToStream ( array , writableStream ) { const writer = writableStream . getWriter (); array . forEach ( chunk => writer . write ( chunk ). catch (() => {})); return writer . close (); } writeArrayToStream ([ 1 , 2 , 3 , 4 , 5 ], writableStream ) . then (() => console . log ( "All done!" )) . catch ( e => console . error ( "Error with the stream: " + e )); You can also write directly to writable streams by acquiring a writer and using itsandmethods. Since writable streams queue any incoming writes, and take care internally to forward them to the underlying sink in sequence, you can indiscriminately write to a writable stream without much ceremony: Note how we use .catch(() => {}) to suppress any rejections from the write() method; we’ll be notified of any fatal errors via a rejection of the close() method, and leaving them un-caught would cause potential unhandledrejection events and console warnings.

close() method. That promise will reject if anything goes wrong with the stream—initializing it, writing to it, or closing it. And it will fulfill once the stream is successfully closed. Often this is all you care about. In the previous example we only paid attention to the success or failure of the entire stream, by looking at the promise returned by the writer’smethod. That promise will reject if anything goes wrong with the stream—initializing it, writing to it, or closing it. And it will fulfill once the stream is successfully closed. Often this is all you care about. However, if you care about the success of writing a specific chunk, you can use the promise returned by the writer’s write() method: writer . write ( "i am a chunk of data" ) . then (() => console . log ( "chunk successfully written!" )) . catch ( e => console . error ( e )); What "success" means is up to a given stream instance (or more precisely, its underlying sink) to decide. For example, for a file stream it could simply mean that the OS has accepted the write, and not necessarily that the chunk has been flushed to disk. Some streams might not be able to give such a signal at all, in which case the returned promise will fulfill immediately.

await the promise returned by write() , consider a modification of the above example, where we continue to use the WritableStreamDefaultWriter interface directly, but we don’t control how many bytes we have to write at a given time. In that case, the async function writeSuppliedBytesForever ( writableStream , getBytes ) { const writer = writableStream . getWriter (); while ( true ) { await writer . ready ; const bytes = getBytes (); writer . write ( bytes ). catch (() => {}); } } To further emphasize how it’s a bad idea tothe promise returned by, consider a modification of the above example, where we continue to use theinterface directly, but we don’t control how many bytes we have to write at a given time. In that case, the backpressure -respecting code looks the same: Unlike the previous example, where—because we were always writing exactly writer.desiredSize bytes each time—the write() and ready promises were synchronized, in this case it’s quite possible that the ready promise fulfills before the one returned by write() does. Remember, the ready promise fulfills when the desired size becomes positive, which might be before the write succeeds (especially in cases with a larger high water mark). In other words, await ing the return value of write() means you never queue up writes in the stream’s internal queue, instead only executing a write after the previous one succeeds, which can result in low throughput.

5.2. WritableStream class Theclass

⚠ MDN WritableStream In only one current engine. Firefox None Safari ? Chrome 59+ Opera 47+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 44+

The WritableStream represents a writable stream.

5.2.1. Interface definition

The Web IDL definition for the WritableStream class is given as follows:

[ Exposed =( Window , Worker , Worklet ), Transferable ] interface WritableStream { constructor ( optional object underlyingSink , optional QueuingStrategy strategy = {}); readonly attribute boolean locked ; Promise < undefined > abort ( optional any reason ); Promise < undefined > close (); WritableStreamDefaultWriter getWriter (); };

5.2.2. Internal slots

Instances of WritableStream are created with the internal slots described in the following table:

Internal Slot Description (non-normative) [[backpressure]] A boolean indicating the backpressure signal set by the controller [[closeRequest]] The promise returned from the writer’s close() method [[controller]] A WritableStreamDefaultController created with the ability to control the state and queue of this stream [[Detached]] A boolean flag set to true when the stream is transferred [[inFlightWriteRequest]] A slot set to the promise for the current in-flight write operation while the underlying sink's write algorithm is executing and has not yet fulfilled, used to prevent reentrant calls [[inFlightCloseRequest]] A slot set to the promise for the current in-flight close operation while the underlying sink's close algorithm is executing and has not yet fulfilled, used to prevent the abort() method from interrupting close [[pendingAbortRequest]] A pending abort request [[state]] A string containing the stream’s current state, used internally; one of " writable ", " closed ", " erroring ", or " errored " [[storedError]] A value indicating how the stream failed, to be given as a failure reason or exception when trying to operate on the stream while in the " errored " state [[writer]] A WritableStreamDefaultWriter instance, if the stream is locked to a writer, or undefined if it is not [[writeRequests]] A list of promises representing the stream’s internal queue of write requests not yet processed by the underlying sink

The [[inFlightCloseRequest]] slot and [[closeRequest]] slot are mutually exclusive. Similarly, no element will be removed from [[writeRequests]] while [[inFlightWriteRequest]] is not undefined. Implementations can optimize storage for these slots based on these invariants.

A pending abort request is a struct used to track a request to abort the stream before that request is finally processed. It has the following items:

promise A promise returned from WritableStreamAbort reason A JavaScript value that was passed as the abort reason to WritableStreamAbort was already erroring A boolean indicating whether or not the stream was in the " erroring " state when WritableStreamAbort was called, which impacts the outcome of the abort request

5.2.3. The underlying sink API

The WritableStream() constructor accepts as its first argument a JavaScript object representing the underlying sink. Such objects can contain any of the following properties:

dictionary UnderlyingSink { UnderlyingSinkStartCallback start ; UnderlyingSinkWriteCallback write ; UnderlyingSinkCloseCallback close ; UnderlyingSinkAbortCallback abort ; any type ; }; callback UnderlyingSinkStartCallback = any ( WritableStreamDefaultController controller ); callback UnderlyingSinkWriteCallback = Promise < undefined > ( any chunk , WritableStreamDefaultController controller ); callback UnderlyingSinkCloseCallback = Promise < undefined > (); callback UnderlyingSinkAbortCallback = Promise < undefined > ( optional any reason );

The controller argument passed to start() and write() is an instance of WritableStreamDefaultController , and has the ability to error the stream. This is mainly used for bridging the gap with non-promise-based APIs, as seen for example in § 10.6 A writable stream with no backpressure or success signals.

5.2.4. Constructor, methods, and properties

⚠ MDN WritableStream/WritableStream In only one current engine. Firefox None Safari ? Chrome 59+ Opera 47+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 44+

new WritableStream( underlyingSink , strategy ) constructor steps are: If underlyingSink is missing, set it to null. Let underlyingSinkDict be underlyingSink , converted to an IDL value of type UnderlyingSink . We cannot declare the underlyingSink argument as having the UnderlyingSink type directly, because doing so would lose the reference to the original object. We need to retain the object so we can invoke the various methods on it. If underlyingSinkDict [" type "] exists, throw a RangeError exception. This is to allow us to add new potential types in the future, without backward-compatibility concerns. Perform ! InitializeWritableStream(this). Let sizeAlgorithm be ! ExtractSizeAlgorithm( strategy ). Let highWaterMark be ? ( strategy , 1). Perform ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink , underlyingSinkDict , highWaterMark , sizeAlgorithm ). Theconstructor steps are:

⚠ MDN WritableStream/locked In only one current engine. Firefox None Safari ? Chrome 59+ Opera 47+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 44+

locked getter steps are: Return ! IsWritableStreamLocked(this). Thegetter steps are:

⚠ MDN WritableStream/abort In only one current engine. Firefox None Safari ? Chrome 59+ Opera 47+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 44+

⚠ MDN WritableStream/getWriter In only one current engine. Firefox None Safari ? Chrome 59+ Opera 47+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 44+

getWriter() method steps are: Return ? AcquireWritableStreamDefaultWriter(this). Themethod steps are:

5.2.5. Transfer via postMessage()

destination.postMessage(ws, { transfer: [ws] }); Sends a WritableStream to another frame, window, or worker. The transferred stream can be used exactly like the original. The original will become locked and no longer directly usable.

dataHolder and value , are: Let deserializedRecord be ! StructuredDeserializeWithTransfer( dataHolder .[[port]], the current Realm). Let port be a deserializedRecord .[[Deserialized]]. Perform ! SetUpCrossRealmTransformWritable( value , port ). Their transfer-receiving steps , givenand, are:

5.3. WritableStreamDefaultWriter class Theclass

⚠ MDN WritableStreamDefaultWriter In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

The WritableStreamDefaultWriter class represents a writable stream writer designed to be vended by a WritableStream instance.

5.3.1. Interface definition

The Web IDL definition for the WritableStreamDefaultWriter class is given as follows:

[ Exposed =( Window , Worker , Worklet )] interface WritableStreamDefaultWriter { constructor ( WritableStream stream ); readonly attribute Promise < undefined > closed ; readonly attribute unrestricted double ? desiredSize ; readonly attribute Promise < undefined > ready ; Promise < undefined > abort ( optional any reason ); Promise < undefined > close (); undefined releaseLock (); Promise < undefined > write ( optional any chunk ); };

5.3.2. Internal slots

Instances of WritableStreamDefaultWriter are created with the internal slots described in the following table:

Internal Slot Description (non-normative) [[closedPromise]] A promise returned by the writer’s closed getter [[readyPromise]] A promise returned by the writer’s ready getter [[stream]] A WritableStream instance that owns this reader

5.3.3. Constructor, methods, and properties

⚠ MDN WritableStreamDefaultWriter/WritableStreamDefaultWriter In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

new WritableStreamDefaultWriter( stream ) constructor steps are: Perform ? SetUpWritableStreamDefaultWriter(this, stream ). Theconstructor steps are:

⚠ MDN WritableStreamDefaultWriter/closed In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

closed getter steps are: Return this.[[closedPromise]]. Thegetter steps are:

⚠ MDN WritableStreamDefaultWriter/desiredSize In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

desiredSize getter steps are: If this.[[stream]] is undefined, throw a TypeError exception. Return ! WritableStreamDefaultWriterGetDesiredSize(this). Thegetter steps are:

⚠ MDN WritableStreamDefaultWriter/ready In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

ready getter steps are: Return this.[[readyPromise]]. Thegetter steps are:

⚠ MDN WritableStreamDefaultWriter/abort In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

⚠ MDN WritableStreamDefaultWriter/close In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

releaseLock() method steps are: Let stream be this.[[stream]]. If stream is undefined, return. Assert: stream .[[writer]] is not undefined. Perform ! WritableStreamDefaultWriterRelease(this). Themethod steps are:

⚠ MDN WritableStreamDefaultWriter/write In only one current engine. Firefox None Safari ? Chrome 59+ Opera 46+ Edge 79+ Edge (Legacy) 16+ IE None Firefox for Android None iOS Safari ? Chrome for Android 59+ Android WebView 59+ Samsung Internet 7.0+ Opera Mobile 43+

5.4. WritableStreamDefaultController class Theclass

⚠ MDN WritableStreamDefaultController In only one current engine. Firefox None Safari ? Chrome 58+ Opera 45+ Edge 79+ Edge (Legacy) 18 IE ? Firefox for Android None iOS Safari ? Chrome for Android 58+ Android WebView 58+ Samsung Internet 7.0+ Opera Mobile 43+

The WritableStreamDefaultController class has methods that allow control of a WritableStream 's state. When constructing a WritableStream , the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate.

5.4.1. Interface definition

The Web IDL definition for the WritableStreamDefaultController class is given as follows:

[ Exposed =( Window , Worker , Worklet )] interface WritableStreamDefaultController { undefined error ( optional any e ); };

5.4.2. Internal slots

Instances of WritableStreamDefaultController are created with the internal slots described in the following table:

The close sentinel is a unique value enqueued into [[queue]], in lieu of a chunk, to signal that the stream is closed. It is only used internally, and is never exposed to web developers.

5.4.3. Methods

controller . error ( e ) Closes the controlled writable stream, making all future interactions with it fail with the given error e . This method is rarely used, since usually it suffices to return a rejected promise from one of the underlying sink's methods. However, it can be useful for suddenly shutting down a stream in response to an event outside the normal lifecycle of interactions with the underlying sink.

⚠ MDN WritableStreamDefaultController/error In no current engines. Firefox None Safari ? Chrome ? Opera ? Edge ? Edge (Legacy) 16+ IE ? Firefox for Android None iOS Safari ? Chrome for Android ? Android WebView ? Samsung Internet ? Opera Mobile ?

error( e ) method steps are: Let state be this.[[stream]].[[state]]. If state is not " writable ", return. Perform ! WritableStreamDefaultControllerError(this, e ). Themethod steps are:

5.4.4. Internal methods

The following are internal methods implemented by each WritableStreamDefaultController instance. The writable stream implementation will call into these.

The reason these are in method form, instead of as abstract operations, is to make it clear that the writable stream implementation is decoupled from the controller implementation, and could in the future be expanded with other controllers, as long as those controllers implemented such internal methods. A similar scenario is seen for readable streams (see § 4.9.2 Interfacing with controllers), where there actually are multiple controller types and as such the counterpart internal methods are used polymorphically.

[[AbortSteps]]( reason ) implements the Let result be the result of performing this.[[abortAlgorithm]], passing reason . Perform ! WritableStreamDefaultControllerClearAlgorithms(this). Return result . implements the [[AbortSteps]] contract. It performs the following steps:

[[ErrorSteps]]() implements the Perform ! ResetQueue(this). implements the [[ErrorSteps]] contract. It performs the following steps:

5.5. Abstract operations

5.5.1. Working with writable streams

The following abstract operations operate on WritableStream instances at a higher level.

AcquireWritableStreamDefaultWriter( stream ) performs the following steps: Let writer be a new WritableStreamDefaultWriter . Perform ? SetUpWritableStreamDefaultWriter( writer , stream ). Return writer . performs the following steps:

CreateWritableStream( startAlgorithm , writeAlgorithm , closeAlgorithm , abortAlgorithm , highWaterMark , sizeAlgorithm ) performs the following steps: Assert: ! IsNonNegativeNumber( highWaterMark ) is true. Let stream be a new WritableStream . Perform ! InitializeWritableStream( stream ). Let controller be a new WritableStreamDefaultController . Perform ? SetUpWritableStreamDefaultController( stream , controller , startAlgorithm , writeAlgorithm , closeAlgorithm , abortAlgorithm , highWaterMark , sizeAlgorithm ). Return stream . performs the following steps: This abstract operation will throw an exception if and only if the supplied startAlgorithm throws.

InitializeWritableStream( stream ) performs the following steps: Set stream .[[state]] to " writable ". Set stream .[[storedError]], stream .[[writer]], stream .[[controller]], stream .[[inFlightWriteRequest]], stream .[[closeRequest]], stream .[[inFlightCloseRequest]], and stream .[[pendingAbortRequest]] to undefined. Set stream .[[writeRequests]] to a new empty list. Set stream .[[backpressure]] to false. performs the following steps:

IsWritableStreamLocked( stream ) performs the following steps: If stream .[[writer]] is undefined, return false. Return true. performs the following steps:

5.5.2. Interfacing with controllers

To allow future flexibility to add different writable stream behaviors (similar to the distinction between default readable streams and readable byte streams), much of the internal state of a writable stream is encapsulated by the WritableStreamDefaultController class.

Each controller class defines two internal methods, which are called by the WritableStream algorithms:

[[AbortSteps]]( reason ) The controller’s steps that run in reaction to the stream being aborted, used to clean up the state stored in the controller and inform the underlying sink. [[ErrorSteps]]() The controller’s steps that run in reaction to the stream being errored, used to clean up the state stored in the controller.

(These are defined as internal methods, instead of as abstract operations, so that they can be called polymorphically by the WritableStream algorithms, without having to branch on which type of controller is present. This is a bit theoretical for now, given that only WritableStreamDefaultController exists so far.)

The rest of this section concerns abstract operations that go in the other direction: they are used by the controller implementation to affect its associated WritableStream object. This translates internal state changes of the controllerinto developer-facing results visible through the WritableStream 's public API.

WritableStreamAddWriteRequest( stream ) performs the following steps: Assert: ! IsWritableStreamLocked( stream ) is true. Assert: stream .[[state]] is " writable ". Let promise be a new promise. Append promise to stream .[[writeRequests]]. Return promise . performs the following steps:

WritableStreamCloseQueuedOrInFlight( stream ) performs the following steps: If stream .[[closeRequest]] is undefined and stream .[[inFlightCloseRequest]] is undefined, return false. Return true. performs the following steps:

WritableStreamDealWithRejection( stream , error ) performs the following steps: Let state be stream .[[state]]. If state is " writable ", Perform ! WritableStreamStartErroring( stream , error ). Return. Assert: state is " erroring ". Perform ! WritableStreamFinishErroring( stream ). performs the following steps:

WritableStreamFinishInFlightClose( stream ) performs the following steps: Assert: stream .[[inFlightCloseRequest]] is not undefined. Resolve stream .[[inFlightCloseRequest]] with undefin