-
Notifications
You must be signed in to change notification settings - Fork 165
/
Copy pathindex.bs
4243 lines (3472 loc) · 200 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class="metadata">
Title: Streams Standard
Group: WHATWG
H1: Streams
Shortname: streams
Repository: whatwg/streams
Inline Github Issues: true
Status: LS
Boilerplate: omit conformance, omit feedback-header
No Editor: true
Abstract: This specification provides APIs for creating, composing, and consuming streams of data.
Abstract: These streams are designed to map efficiently to low-level I/O primitives, and allow easy
Abstract: composition with built-in backpressure and queuing. On top of streams, the web platform can
Abstract: build higher-level abstractions, such as filesystem or socket APIs, while at the same time
Abstract: users can use the supplied tools to build their own streams which integrate well with those
Abstract: of the web platform.
Logo: https://resources.whatwg.org/logo-streams.svg
Use Dfn Panels: yes
!Participate: <a href="https://github.com/whatwg/streams">GitHub whatwg/streams</a> (<a href="https://github.com/whatwg/streams/issues/new">new issue</a>, <a href="https://github.com/whatwg/streams/issues">open issues</a>)
!Participate: <a href="https://wiki.whatwg.org/wiki/IRC">IRC: #whatwg on Freenode</a>
!Commits: <a href="https://github.com/whatwg/streams/commits">GitHub whatwg/streams/commits</a>
!Commits: [SNAPSHOT-LINK]
!Commits: <a href="https://twitter.com/streamsstandard">@streamsstandard</a>
!Translation (non-normative): <a href="https://triple-underscore.github.io/Streams-ja.html" rel="alternate" title="Japanese" hreflang="jp" lang="jp">日本語</a>
Opaque Elements: emu-alg
Ignored Vars: e
</pre>
<pre class="anchors">
urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
text: %Uint8Array%; url: #sec-typedarray-objects; type: constructor
text: ArrayBuffer; url: #sec-arraybuffer-objects; type: interface
text: DataView; url: #sec-dataview-objects; type: interface
text: Uint8Array; url: #sec-typedarray-objects; type: interface
text: typed array; url: #sec-typedarray-objects; type: dfn
text: the typed array constructors table; url: #table-49; type: dfn
text: TypeError; url: #sec-native-error-types-used-in-this-standard-typeerror; type: exception
text: Invoke; url: #sec-invoke; type: abstract-op
</pre>
<style>
.note + .example, .note + .note { margin-top: 1em; }
emu-val { font-weight: bold; }
emu-alg > ol, emu-alg > ol ol ol ol { list-style-type: decimal; }
emu-alg > ol ol, emu-alg > ol ol ol ol ol { list-style-type: lower-alpha; }
emu-alg > ol ol ol, emu-alg > ol ol ol ol ol ol { list-style-type: lower-roman; }
emu-alg li { margin: 0; }
.heading[aoid] .annotation {
background-color: beige;
border: 1px solid black;
border-radius: 3px;
cursor: help;
display: inline-block;
font-size: 70%;
font-weight: normal;
padding: 1px 2px;
}
</style>
<script src="https://resources.whatwg.org/file-issue.js" async></script>
<script src="https://resources.whatwg.org/commit-snapshot-shortcut-key.js" async></script>
<h2 id="intro">Introduction</h2>
<em>This section is non-normative.</em>
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 <a>readable streams</a>,
<a>writable streams</a>, and <a>transform streams</a>.
This standard provides the base stream primitives which other parts of the web platform can use to expose their
streaming data. For example, [[FETCH]] could expose request bodies as a writable stream, or response bodies as a
readable stream. More generally, the platform is full of streaming abstractions waiting to be expressed as streams:
multimedia streams, file streams, interprocess 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:
<ul>
<li> Video effects: piping a readable video stream through a transform stream that applies effects in real time.
<li> Decompression: piping a file stream through a transform stream that selectively decompresses files from a
<kbd>.tgz</kbd> archive, turning them into <code>img</code> elements as the user scrolls through an image gallery.
<li> 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 <code>fetch</code>
hook of a service worker [[SERVICE-WORKERS]], this would allow developers to transparently polyfill new image
formats.
</ul>
The APIs described here provide unifying abstraction for all such streams, encouraging an ecosystem to grow around
these shared and composable interfaces. At the same time, they have been carefully designed to map efficiently to
low-level I/O concerns, and to encapsulate the trickier issues (such as <a>backpressure</a>) that come along for the
ride.
<h2 id="model">Model</h2>
A <dfn>chunk</dfn> 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.
<h3 id="rs-model">Readable Streams</h3>
A <dfn>readable stream</dfn> represents a source of data, from which you can read. In other words, data comes
<em>out</em> of a readable stream.
Although a readable stream can be created with arbitrary behavior, most readable streams wrap a lower-level I/O source,
called the <dfn>underlying source</dfn>. There are two types of underlying source: push sources and pull sources.
<dfn lt="push source">Push sources</dfn> 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.
<dfn lt="pull source">Pull sources</dfn> 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.
<a>Chunks</a> are enqueued into the stream by the stream's <a>underlying source</a>. They can then be read one at a
time via the stream's public interface.
Code that reads from a readable stream using its public interface is known as a <dfn>consumer</dfn>.
Consumers also have the ability to <dfn lt="cancel a readable stream">cancel</dfn> a readable stream. This indicates
that the consumer has lost interest in the stream, and will immediately close the stream, throw away any queued
<a>chunks</a>, and execute any cancellation mechanism of the <a>underlying source</a>.
Consumers can also <dfn lt="tee a readable stream">tee</dfn> a readable stream. This will
<a lt="locked to a reader">lock</a> the stream, making it no longer directly usable; however, it will create two new
streams, called <dfn lt="branches of a readable stream tee">branches</dfn>, which can be consumed independently.
For streams representing bytes, an extended version of the <a>readable stream</a> is provided to handle bytes
efficiently, in particular by minimizing copies. The <a>underlying source</a> for such a readable stream is called
a <dfn>underlying byte source</dfn>. A readable stream whose underlying source is an underlying byte source is sometimes
called a <dfn>readable byte stream</dfn>.
<h3 id="ws-model">Writable Streams</h3>
A <dfn>writable stream</dfn> represents a destination for data, into which you can write. In other words, data goes
<em>in</em> to a writable stream.
Analogously to readable streams, most writable streams wrap a lower-level I/O sink, called the
<dfn>underlying sink</dfn>. 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.
<a>Chunks</a> are written to the stream via its public interface, and are passed one at a time to the stream's
<a>underlying sink</a>.
Code that writes into a writable stream using its public interface is known as a <dfn>producer</dfn>.
Producers also have the ability to <dfn lt="abort a writable stream">abort</dfn> a writable stream. 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 <a>underlying sink</a>.
<h3 id="ts-model">Transform Streams</h3>
A <dfn>transform stream</dfn> consists of a pair of streams: a writable stream, and a readable stream.
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.
Some examples of transform streams include:
<ul>
<li>A GZIP compressor, to which uncompressed bytes are written and from which compressed bytes are read;</li>
<li>A video decoder, to which encoded bytes are written and from which uncompressed video frames are read;</li>
<li>A text decoder, to which bytes are written and from which strings are read;</li>
<li>A CSV-to-JSON converter, to which strings representing lines of a CSV file are written and from which
corresponding JavaScript objects are read.
</ul>
<h3 id="pipe-chains">Pipe Chains and Backpressure</h3>
Streams are primarily used by <dfn>piping</dfn> them to each other. A readable stream can be piped directly to a
writable stream, or it can be piped through one or more transform streams first.
A set of streams piped together in this way is referred to as a <dfn>pipe chain</dfn>. In a pipe chain, the
<dfn>original source</dfn> is the <a>underlying source</a> of the first readable stream in the chain; the
<dfn>ultimate sink</dfn> is the <a>underlying sink</a> of the final writable stream in the chain.
Once a pipe chain is constructed, it can be used to propagate signals regarding how fast <a>chunks</a> 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 <dfn>backpressure</dfn>.
When <a lt="tee a readable stream">teeing</a> a readable stream, the <a>backpressure</a> signals from its two
<a href="branches of a readable stream tee">branches</a> will aggregate, such that if neither branch is read from, a
backpressure signal will be sent to the <a>underlying source</a> of the original stream.
<!-- TODO when we have writable stream writers
Piping a readable stream <a href="locked to a reader">locks</a> the readable stream, preventing it from being accessed
-->
<h3 id="queuing-strategies">Internal Queues and Queuing Strategies</h3>
Both readable and writable streams maintain <dfn>internal queues</dfn>, which they use for similar purposes. In the
case of a readable stream, the internal queue contains <a>chunks</a> that have been enqueued by the <a>underlying
source</a>, but not yet read by the consumer. In the case of a writable stream, the internal queue contains
<a>chunks</a> which have been written to the stream by the producer, but not yet processed and acknowledged by the
<a>underlying sink</a>.
A <dfn>queuing strategy</dfn> is an object that determines how a stream should signal <a>backpressure</a> based on
the state of its <a>internal queue</a>. The queuing strategy assigns a size to each <a>chunk</a>, and compares the
total size of all chunks in the queue to a specified number, known as the <dfn>high water mark</dfn>. The resulting
difference, high water mark minus total size, is used to determine the
<dfn lt="desired size to fill a stream's internal queue">desired size to fill the stream's queue</dfn>.
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.
<div class="example" id="example-simple-queuing-strategy">
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.
</div>
<h3 id="locking">Locking</h3>
A <dfn>readable stream reader</dfn>, or simply reader, is an object that allows direct reading of <a>chunks</a> from a
<a>readable stream</a>. Without a reader, a <a>consumer</a> can only perform high-level operations on the readable
stream: <a lt="cancel a readable stream">canceling</a> the stream, or <a>piping</a> the readable stream to a writable
stream.
Similarly, a <dfn>writable stream writer</dfn>, or simply writer, is an object that allows direct writing of
<a>chunks</a> to a <a>writable stream</a>. Without a writer, a <a>producer</a> can only perform the high-level
operations of <a lt="abort a writable stream">aborting</a> the stream or <a>piping</a> a readable stream to the writable
stream.
(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
<dfn lt="locked to a reader|locked to a writer">locked</dfn>, and that the reader or writer is <dfn
lt="active|active reader|active writer">active</dfn>.
A reader or writer also has the capability to <dfn lt="release a lock|release a read lock|release a write lock">release
its lock</dfn>, which makes it no longer active, and allows further readers or writers to be acquired.
A <a>readable byte stream</a> has the ability to vend two types of readers: <dfn>default readers</dfn> and <dfn>BYOB
readers</dfn>. BYOB ("bring your own buffer") readers allow reading into a developer-supplied buffer, thus minimizing
copies.
<h2 id="rs">Readable Streams</h2>
<h3 id="rs-intro">Using Readable Streams</h3>
<div class="example" id="example-basic-pipe-to">
The simplest way to consume a readable stream is to simply <a lt="piping">pipe</a> it to a <a>writable stream</a>.
This ensures that <a>backpressure</a> is respected, and any errors (either writing or reading) are propagated through
the chain:
<pre><code class="lang-javascript">
readableStream.pipeTo(writableStream)
.then(() => console.log("All data successfully written!"))
.catch(e => console.error("Something went wrong!", e));
</code></pre>
</div>
<div class="example" id="example-pipe-as-chunks-receiver">
If you simply want to be alerted of each new chunk from a readable stream, you can <a lt="piping">pipe</a> it to a
new <a>writable stream</a> that you custom-create for that purpose:
<pre><code class="lang-javascript">
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);
}
}));
</code></pre>
By returning promises from your <code>write</code> implementation, you can signal <a>backpressure</a> to the readable
stream.
</div>
<div class="example" id="example-manual-read">
Although readable streams will usually be used by piping them to a writable stream, you can also read them directly
by acquiring a <a lt="readable stream reader">reader</a> and using its <code>read()</code> method to get successive
chunks. For example, this code logs the next <a>chunk</a> in the stream, if available:
<pre><code class="lang-javascript">
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)
);
</code></pre>
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 <a>piping</a> and <a lt="tee a readable stream">teeing</a>.
</div>
<div class="example" id="example-manual-read-bytes">
The above example showed using the readable stream's <a>default reader</a>. If the stream is a <a>readable byte
stream</a>, you can also acquire a <a>BYOB reader</a> 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:
<pre><code class="lang-javascript">
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);
});
}
</code></pre>
An important thing to note here is that the final <code>buffer</code> value is different from the
<code>startingAB</code>, but it (and all intermediate buffers) shares the same backing memory allocation. At each
step, the buffer is <a abstract-op lt="Transfer">transferred</a> to a new {{ArrayBuffer}} object. The
<code>newView</code> is a new {{Uint8Array}}, with that {{ArrayBuffer}} object as its <code>buffer</code> property,
the offset that bytes were written to as its <code>byteOffset</code> property, and the number of bytes that were
written as its <code>byteLength</code> property.
</div>
<h3 id="rs-class" interface lt="ReadableStream">Class <code>ReadableStream</code></h3>
The {{ReadableStream}} class is a concrete instance of the general <a>readable stream</a> concept. It is
adaptable to any <a>chunk</a> type, and maintains an internal queue to keep track of data supplied by the <a>underlying
source</a> but not yet read by any consumer.
<h4 id="rs-class-definition">Class Definition</h4>
<em>This section is non-normative.</em>
If one were to write the {{ReadableStream}} class in something close to the syntax of [[!ECMASCRIPT]], it would look
like
<pre><code class="lang-javascript">
class ReadableStream {
constructor(underlyingSource = {}, { size, highWaterMark } = {})
get locked()
cancel(reason)
getReader()
pipeThrough({ writable, readable }, options)
pipeTo(dest, { preventClose, preventAbort, preventCancel } = {})
tee()
}
</code></pre>
<h4 id="rs-internal-slots">Internal Slots</h4>
Instances of {{ReadableStream}} are created with the internal slots described in the following table:
<table>
<thead>
<tr>
<th>Internal Slot</th>
<th>Description (<em>non-normative</em>)</th>
</tr>
</thead>
<tr>
<td>\[[disturbed]]
<td>A boolean flag set to <emu-val>true</emu-val> when the stream has been read from or canceled
</tr>
<tr>
<td>\[[readableStreamController]]
<td>A {{ReadableStreamDefaultController}} or {{ReadableByteStreamController}} created with the ability to control
the state and queue of this stream; also used for the IsReadableStream brand check
</tr>
<tr>
<td>\[[reader]]
<td>A {{ReadableStreamDefaultReader}} or {{ReadableStreamBYOBReader}} instance, if the stream is <a>locked to a
reader</a>, or <emu-val>undefined</emu-val> if it is not
</tr>
<tr>
<td>\[[state]]
<td>A string containing the stream's current state, used internally; one of <code>"readable"</code>,
<code>"closed"</code>, or <code>"errored"</code>
</tr>
<tr>
<td>\[[storedError]]
<td>A value indicating how the stream failed, to be given as a failure reason or exception when trying to operate
on an errored stream
</tr>
</table>
<h4 id="rs-constructor" constructor for="ReadableStream" lt="ReadableStream(underlyingSource, queuingStrategy)">new
ReadableStream(<var>underlyingSource</var> = {}, { <var>size</var>, <var>highWaterMark</var> } = {})</h4>
<div class="note">
The <code>underlyingSource</code> object passed to the constructor can implement any of the following methods to
govern how the constructed stream instance behaves:
<ul>
<li> <code>start(controller)</code> is called immediately, and is typically used to adapt a <a>push
source</a> by setting up relevant event listeners, or to acquire access to a <a>pull source</a>. If this process
is asynchronous, it can return a promise to signal success or failure.
<li> <code>pull(controller)</code> is called when the stream's <a>internal queue</a> of chunks is not full, and
will be called repeatedly until the queue reaches its <a>high water mark</a>. If <code>pull</code> returns a
promise, then <code>pull</code> will not be called again until that promise fulfills; if the promise rejects, the
stream will become errored.
<li> <code>cancel(reason)</code> is called when the consumer signals that they are no longer interested in the
stream. It should perform any actions necessary to release access to the <a>underlying source</a>. If this
process is asynchronous, it can return a promise to signal success or failure.
</ul>
Both <code>start</code> and <code>pull</code> are given the ability to manipulate the stream's internal queue and
state via the passed <code>controller</code> object. This is an example of the
<a href="https://blog.domenic.me/the-revealing-constructor-pattern/">revealing constructor pattern</a>.
If the <code>underlyingSource</code> object contains a property <code>type</code> set to <code>"bytes"</code>, this
<a>readable stream</a> is a <a>readable byte stream</a>, and can successfully vend <a>BYOB readers</a>. In that case,
the passed <code>controller</code> object will be an instance of {{ReadableByteStreamController}}. Otherwise, it will
be an instance of {{ReadableStreamDefaultController}}.
For <a>readable byte streams</a>, <code>underlyingSource</code> can also contain a property
<code>autoAllocateChunkSize</code>, which can be set to a positive integer to enable the auto-allocation feature for
this stream. In that case, when a <a>consumer</a> uses a <a>default reader</a>, the stream implementation will
automatically allocate an {{ArrayBuffer}} of the given size, and call the <a>underlying source</a> code
as if the <a>consumer</a> was using a <a>BYOB reader</a>. This can cut down on the amount of code needed when writing
the <a>underlying source</a> implementation, as can be seen by comparing [[#example-rbs-push]] without auto-allocation
to [[#example-rbs-pull]] with auto-allocation.
The constructor also accepts a second argument containing the <a>queuing strategy</a> object with
two properties: a non-negative number <code>highWaterMark</code>, and a function <code>size(chunk)</code>. The
supplied <code>strategy</code> could be an instance of the built-in {{CountQueuingStrategy}} or
{{ByteLengthQueuingStrategy}} classes, or it could be custom. If no strategy is supplied, the default
behavior will be the same as a {{CountQueuingStrategy}} with a <a>high water mark</a> of 1.
</div>
<emu-alg>
1. Set *this*.[[state]] to `"readable"`.
1. Set *this*.[[reader]] and *this*.[[storedError]] to *undefined*.
1. Set *this*.[[disturbed]] to *false*.
1. Set *this*.[[readableStreamController]] to *undefined*.
1. Let _type_ be ? GetV(_underlyingSource_, `"type"`).
1. Let _typeString_ be ? ToString(_type_).
1. If _typeString_ is `"bytes"`,
1. If _highWaterMark_ is *undefined*, let _highWaterMark_ be *0*.
1. Set *this*.[[readableStreamController]] to ? Construct(`<a idl>ReadableByteStreamController</a>`, « *this*,
_underlyingSource_, _highWaterMark_ »).
1. Otherwise, if _type_ is *undefined*,
1. If _highWaterMark_ is *undefined*, let _highWaterMark_ be *1*.
1. Set *this*.[[readableStreamController]] to ? Construct(`<a idl>ReadableStreamDefaultController</a>`, « *this*,
_underlyingSource_, _size_, _highWaterMark_ »).
1. Otherwise, throw a *RangeError* exception.
</emu-alg>
<h4 id="rs-prototype">Properties of the {{ReadableStream}} Prototype</h4>
<h5 id="rs-locked" attribute for="ReadableStream" lt="locked">get locked</h5>
<div class="note">
The <code>locked</code> getter returns whether or not the readable stream is <a>locked to a reader</a>.
</div>
<emu-alg>
1. If ! IsReadableStream(*this*) is *false*, throw a *TypeError* exception.
1. Return ! IsReadableStreamLocked(*this*).
</emu-alg>
<h5 id="rs-cancel" method for="ReadableStream">cancel(<var>reason</var>)</h5>
<div class="note">
The <code>cancel</code> method <a lt="cancel a readable stream">cancels</a> the stream, signaling a loss of interest
in the stream by a consumer. The supplied <code>reason</code> argument will be given to the underlying source, which
may or may not use it.
</div>
<emu-alg>
1. If ! IsReadableStream(*this*) is *false*, return <a>a promise rejected with</a> a *TypeError* exception.
1. If ! IsReadableStreamLocked(*this*) is *true*, return <a>a promise rejected with</a> a *TypeError* exception.
1. Return ! ReadableStreamCancel(*this*, _reason_).
</emu-alg>
<h5 id="rs-get-reader" method for="ReadableStream">getReader({ <var>mode</var> } = {})</h5>
<div class="note">
The <code>getReader</code> method creates a reader of the type specified by the <code>mode</code> option and <a
lt="locked to a reader">locks</a> the stream to the new reader. While the stream is locked, no other reader can be
acquired until this one is <a lt="release a read lock">released</a>.
This functionality is especially useful for creating abstractions that desire the ability to consume a stream in its
entirety. By getting a reader for the stream, you can ensure nobody else can interleave reads with yours or cancel
the stream, which would interfere with your abstraction.
When <code>mode</code> is <emu-val>undefined</emu-val>, the method creates a <a>default reader</a> (an instance of
{{ReadableStreamDefaultReader}}). The reader provides the ability to directly read individual <a>chunks</a> from the
stream via the reader's {{ReadableStreamDefaultReader/read()}} method.
When <code>mode</code> is <code>"byob"</code>, the <code>getReader</code> method creates a <a>BYOB reader</a> (an
instance of {{ReadableStreamBYOBReader}}). This feature only works on <a>readable byte streams</a>, i.e. streams which
were constructed specifically with the ability to handle "bring your own buffer" reading. The reader provides the
ability to directly read individual <a>chunks</a> from the stream via the reader's {{ReadableStreamBYOBReader/read()}}
method, into developer-supplied buffers, allowing more precise control over allocation.
</div>
<emu-alg>
1. If ! IsReadableStream(*this*) is *false*, throw a *TypeError* exception.
1. If _mode_ is `"byob"`,
1. If ! IsReadableByteStreamController(*this*.[[readableStreamController]]) is *false*, throw a *TypeError*
exception.
1. Return ? AcquireReadableStreamBYOBReader(*this*).
1. If _mode_ is *undefined*, return ? AcquireReadableStreamDefaultReader(*this*).
1. Throw a *RangeError* exception.
</emu-alg>
<div class="example" id="example-read-all-chunks">
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 <a>chunks</a>.
<pre><code class="lang-javascript">
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();
});
}
}
</code></pre>
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
<a lt="cancel a readable stream">canceling</a> the stream.
</div>
<h5 id="rs-pipe-through" method for="ReadableStream" lt="pipeThrough(transform, options)">pipeThrough({
<var>writable</var>, <var>readable</var> }, <var>options</var>)</h5>
<div class="note">
The <code>pipeThrough</code> method provides a convenient, chainable way of <a>piping</a> this <a>readable stream</a>
through a <a>transform stream</a> (or any other <code>{ writable, readable }</code> pair). It simply pipes the stream
into the writable side of the supplied pair, and returns the readable side for further use.
Piping a stream will generally <a lt="locked to a reader">lock</a> it for the duration of the pipe, preventing any
other consumer from acquiring a reader.
This method is intentionally generic; it does not require that its <emu-val>this</emu-val> value be a
{{ReadableStream}} object. It also does not require that its <code>writable</code> argument be a {{WritableStream}}
instance, or that its <code>readable</code> argument be a {{ReadableStream}} instance.
</div>
<emu-alg>
1. Perform ? Invoke(*this*, `"pipeTo"`, « _writable_, _options_ »).
1. Return _readable_.
</emu-alg>
<div class="example" id="example-pipe-chain">
A typical example of constructing <a>pipe chain</a> using {{ReadableStream/pipeThrough(transform, options)}} would
look like
<pre><code class="lang-javascript">
httpResponseBody
.pipeThrough(decompressorTransform)
.pipeThrough(ignoreNonImageFilesTransform)
.pipeTo(mediaGallery);
</code></pre>
</div>
<h5 id="rs-pipe-to" method for="ReadableStream" lt="pipeTo(dest, options)">pipeTo(<var>dest</var>, {
<var>preventClose</var>, <var>preventAbort</var>, <var>preventCancel</var> } = {})</h5>
<div class="note">
The <code>pipeTo</code> method <a lt="piping">pipes</a> this <a>readable stream</a> to a given <a>writable
stream</a>. The way in which the piping process behaves under various error conditions can be customized with a
number of passed options. It returns a promise that fulfills when the piping process completes successfully, or
rejects if any errors were encountered.
Piping a stream will <a lt="locked to a reader">lock</a> it for the duration of the pipe, preventing any other
consumer from acquiring a reader.
Errors and closures of the source and destination streams propagate as follows:
<ul>
<li><p>An error in the source <a>readable stream</a> will <a lt="abort a writable stream">abort</a> the destination
<a>writable stream</a>, unless <code>preventAbort</code> is truthy. The returned promise will be rejected with the
source's error, or with any error that occurs during aborting the destination.</p></li>
<li><p>An error in the destination <a>writable stream</a> will <a lt="cancel a readable stream">cancel</a> the
source <a>readable stream</a>, unless <code>preventCancel</code> is truthy. The returned promise will be rejected
with the destination's error, or with any error that occurs during canceling the source.</p></li>
<li><p>When the source <a>readable stream</a> closes, the destination <a>writable stream</a> will be closed, unless
<code>preventClose</code> is true. The returned promise will be fulfilled once this process completes, unless an
error is encountered while closing the destination, in which case it will be rejected with that error.</p></li>
<li><p>If the destination <a>writable stream</a> starts out closed or closing, the source <a>readable stream</a>
will be <a lt="cancel a readable stream">canceled</a>, unless <code>preventCancel</code> is true. The returned
promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs
during canceling the source.</p></li>
</ul>
</div>
<emu-alg>
1. If ! IsReadableStream(*this*) is *false*, return a promise rejected with a *TypeError* exception.
1. If ! IsWritableStream(_dest_) is *false*, return a promise rejected with a *TypeError* exception.
1. Set _preventClose_ to ! ToBoolean(_preventClose_), set _preventAbort_ to ! ToBoolean(_preventAbort_), and set
_preventCancel_ to ! ToBoolean(_preventCancel_).
1. If ! IsReadableStreamLocked(*this*) is *true*, return a promise rejected with a *TypeError* exception.
1. If ! IsWritableStreamLocked(_dest_) is *true*, return a promise rejected with a *TypeError* exception.
1. If ! IsReadableByteStreamController(*this*.[[readableStreamController]]) is true, let _reader_ be either !
AcquireReadableStreamBYOBReader(*this*) or ! AcquireReadableStreamDefaultReader(*this*), at the user agent's
discretion.
1. Otherwise, let _reader_ be ! AcquireReadableStreamDefaultReader(*this*).
1. Let _writer_ be ! AcquireWritableStreamDefaultWriter(_dest_).
1. Let _shuttingDown_ be *false*.
1. Let _promise_ be <a>a new promise</a>.
1. <a>In parallel</a>, using _reader_ and _writer_, read all <a>chunks</a> from *this* and write them to _dest_. Due
to the locking provided by the reader and writer, the exact manner in which this happens is not observable to
author code, and so there is flexibility in how this is done. The following constraints apply regardless of the
exact algorithm used:
* <strong>Public API must not be used:</strong> while reading or writing, or performing any of the operations
below, the JavaScript-modifiable reader, writer, and stream APIs (i.e. methods on the appropriate prototypes)
must not be used. Instead, the streams must be manipulated directly.
* <strong>Backpressure must be enforced:</strong>
* While WritableStreamDefaultWriterGetDesiredSize(_writer_) is ≤ *0* or is *null*, the user agent must not read
from _reader_.
* If _reader_ is a <a>BYOB reader</a>, WritableStreamDefaultWriterGetDesiredSize(_writer_) should be used to
determine the size of the chunks read from _reader_.
* Otherwise, WritableStreamDefaultWriterGetDesiredSize(_writer_) may be used to determine the flow rate
heuristically, e.g. by delaying reads while it is judged to be "low" compared to the size of chunks that have
been typically read.
* <strong>Shutdown must stop all activity:</strong> if _shuttingDown_ becomes *true*, the user agent must not
initiate further reads from _reader_ or writes to _writer_. (Ongoing reads and writes may finish.) In particular,
the user agent must check the below conditions on *this*.[[state]] and _dest_.[[state]] before performing any
reads or writes, since they might lead to immediate shutdown.
* <strong>Errors must be propagated forward:</strong> if *this*.[[state]] is or becomes `"errored"`, then
1. If _preventAbort_ is *false*, <a href="#rs-pipeTo-shutdown-with-action">shutdown with an action</a> of !
WritableStreamAbort(_dest_, *this*.[[storedError]]) and with *this*.[[storedError]].
1. Otherwise, <a href="#rs-pipeTo-shutdown">shutdown</a> with *this*.[[storedError]].
* <strong>Errors must be propagated backward:</strong> if _dest_.[[state]] is or becomes `"errored"`, then
1. If _preventCancel_ is *false*, <a href="#rs-pipeTo-shutdown-with-action">shutdown with an action</a> of !
ReadableStreamCancel(*this*, _dest_.[[storedError]]) and with _dest_.[[storedError]].
1. Otherwise, <a href="#rs-pipeTo-shutdown">shutdown</a> with _dest_.[[storedError]].
* <strong>Closing must be propagated forward:</strong> if *this*.[[state]] is or becomes `"closed"`, then
1. If _preventClose_ is *false*, <a href="#rs-pipeTo-shutdown-with-action">shutdown with an action</a> of !
WritableStreamDefaultWriterCloseWithErrorPropagation(_writer_).
1. Otherwise, <a href="#rs-pipeTo-shutdown">shutdown</a>.
* <strong>Closing must be propagated backward:</strong> if _dest_.[[state]] is `"closing"` or `"closed"`, then
1. Let _destClosed_ be a new *TypeError*.
1. If _preventCancel_ is *false*, <a href="#rs-pipeTo-shutdown-with-action">shutdown with an action</a> of !
ReadableStreamCancel(*this*, _destClosed_) and with _destClosed_.
1. Otherwise, <a href="#rs-pipeTo-shutdown">shutdown</a> with _destClosed_.
* <i id="rs-pipeTo-shutdown-with-action">Shutdown with an action</i>: if any of the above requirements ask to
shutdown with an action _action_, optionally with an error _originalError_, then:
1. If _shuttingDown_ is *true*, abort these substeps.
1. Set _shuttingDown_ to *true*.
1. Wait until any ongoing write finishes (i.e. the corresponding promises settle).
1. Let _p_ be the result of performing _action_.
1. <a>Upon fulfillment</a> of _p_, <a href="#rs-pipeTo-finalize">finalize</a>, passing along _originalError_ if
it was given.
1. <a>Upon rejection</a> of _p_ with reason _newError_, <a href="#rs-pipeTo-finalize">finalize</a> with
_newError_.
* <i id="rs-pipeTo-shutdown">Shutdown</i>: if any of the above requirements or steps ask to shutdown, optionally
with an error _error_, then:
1. If _shuttingDown_ is *true*, abort these substeps.
1. Set _shuttingDown_ to *true*.
1. Wait until any ongoing write finishes (i.e. the corresponding promises settle).
1. <a href="#rs-pipeTo-finalize">Finalize</a>, passing along _error_ if it was given.
* <i id="rs-pipeTo-finalize">Finalize</i>: both forms of shutdown will eventually ask to finalize, optionally with
an error _error_, which means to perform the following steps:
1. Perform ! WritableStreamDefaultWriterRelease(_writer_).
1. Perform ! ReadableStreamReaderGenericRelease(_reader_).
1. If _error_ was given, <a>reject</a> _promise_ with _error_.
1. Otherwise, <a>resolve</a> _promise_ with *undefined*.
1. Return _promise_.
</emu-alg>
<h5 id="rs-tee" method for="ReadableStream">tee()</h5>
<div class="note">
The <code>tee</code> method <a lt="tee a readable stream">tees</a> this readable stream, returning a two-element
array containing the two resulting branches as new {{ReadableStream}} instances.
Teeing a stream will <a lt="locked to a reader">lock</a> it, preventing any other consumer from acquiring a reader.
To <a lt="cancel a readable stream">cancel</a> the stream, cancel both of the resulting branches; a composite
cancellation reason will then be propagated to the stream's <a>underlying source</a>.
Note that the <a>chunks</a> seen in each branch will be the same object. If the chunks are not immutable, this could
allow interference between the two branches. (<a href="https://github.com/whatwg/streams/issues/new">Let us know</a>
if you think we should add an option to <code>tee</code> that creates <a abstract-op lt="StructuredClone">structured
clones</a> of the chunks for each branch.)
</div>
<emu-alg>
1. If ! IsReadableStream(*this*) is *false*, throw a *TypeError* exception.
1. Let _branches_ be ? ReadableStreamTee(*this*, *false*).
1. Return ! CreateArrayFromList(_branches_).
</emu-alg>
<div class="example" id="example-tee-and-pipe">
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 stream <code>cacheEntry</code> representing an
on-disk file, and another writable stream <code>httpRequestBody</code> representing an upload to a remote server,
you could pipe the same readable stream to both destinations at once:
<pre><code class="lang-javascript">
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));
</code></pre>
</div>
<h3 id="rs-abstract-ops">General Readable Stream Abstract Operations</h3>
The following abstract operations, unlike most in this specification, are meant to be generally useful by other
specifications, instead of just being part of the implementation of this spec's classes.
<h4 id="acquire-readable-stream-byob-reader" aoid="AcquireReadableStreamBYOBReader"
throws>AcquireReadableStreamBYOBReader ( <var>stream</var> )</h4>
This abstract operation is meant to be called from other specifications that may wish to acquire a <a>BYOB reader</a>
for a given stream.
<emu-alg>
1. Return ? Construct(`<a idl>ReadableStreamBYOBReader</a>`, « _stream_ »).
</emu-alg>
<h4 id="acquire-readable-stream-reader" aoid="AcquireReadableStreamDefaultReader" throws
export>AcquireReadableStreamDefaultReader ( <var>stream</var> )</h4>
This abstract operation is meant to be called from other specifications that may wish to acquire a <a>default
reader</a> for a given stream.
<emu-alg>
1. Return ? Construct(`<a idl>ReadableStreamDefaultReader</a>`, « _stream_ »).
</emu-alg>
<h4 id="is-readable-stream" aoid="IsReadableStream" nothrow>IsReadableStream ( <var>x</var> )</h4>
<emu-alg>
1. If Type(_x_) is not Object, return *false*.
1. If _x_ does not have a [[readableStreamController]] internal slot, return *false*.
1. Return *true*.
</emu-alg>
<h4 id="is-readable-stream-disturbed" aoid="IsReadableStreamDisturbed" nothrow export>IsReadableStreamDisturbed (
<var>stream</var> )</h4>
This abstract operation is meant to be called from other specifications that may wish to query whether or not a
readable stream has ever been read from or canceled.
<emu-alg>
1. Assert: ! IsReadableStream(_stream_) is *true*.
1. Return _stream_.[[disturbed]].
</emu-alg>
<h4 id="is-readable-stream-locked" aoid="IsReadableStreamLocked" nothrow export>IsReadableStreamLocked (
<var>stream</var> )</h4>
This abstract operation is meant to be called from other specifications that may wish to query whether or not a
readable stream is <a>locked to a reader</a>.
<emu-alg>
1. Assert: ! IsReadableStream(_stream_) is *true*.
1. If _stream_.[[reader]] is *undefined*, return *false*.
1. Return *true*.
</emu-alg>
<h4 id="readable-stream-tee" aoid="ReadableStreamTee" throws export>ReadableStreamTee ( <var>stream</var>,
<var>cloneForBranch2</var> )</h4>
This abstract operation is meant to be called from other specifications that may wish to <a lt="tee a readable
stream">tee</a> a given readable stream.
The second argument, <var>cloneForBranch2</var>, governs whether or not the data from the original stream will be <a
abstract-op lt="StructuredClone">structured cloned</a> before appearing in the second of the returned branches. This is
useful for scenarios where both branches are to be consumed in such a way that they might otherwise interfere with each
other, such as by <a abstract-op lt="Transfer">transfering</a> their <a>chunks</a>. However, it does introduce a
noticable asymmetry between the two branches. [[!HTML]]
<emu-alg>
1. Assert: ! IsReadableStream(_stream_) is *true*.
1. Assert: Type(_cloneForBranch2_) is Boolean.
1. Let _reader_ be ? AcquireReadableStreamDefaultReader(_stream_).
1. Let _teeState_ be Record {[[closedOrErrored]]: *false*, [[canceled1]]: *false*, [[canceled2]]: *false*,
[[reason1]]: *undefined*, [[reason2]]: *undefined*, [[promise]]: <a>a new promise</a>}.
1. Let _pull_ be a new <a>ReadableStreamTee pull function</a>.
1. Set _pull_.[[reader]] to _reader_, _pull_.[[teeState]] to _teeState_, and _pull_.[[cloneForBranch2]] to
_cloneForBranch2_.
1. Let _cancel1_ be a new <a>ReadableStreamTee branch 1 cancel function</a>.
1. Set _cancel1_.[[stream]] to _stream_ and _cancel1_.[[teeState]] to _teeState_.
1. Let _cancel2_ be a new <a>ReadableStreamTee branch 2 cancel function</a>.
1. Set _cancel2_.[[stream]] to _stream_ and _cancel2_.[[teeState]] to _teeState_.
1. Let _underlyingSource1_ be ! ObjectCreate(%ObjectPrototype%).
1. Perform ! CreateDataProperty(_underlyingSource1_, `"pull"`, _pull_).
1. Perform ! CreateDataProperty(_underlyingSource1_, `"cancel"`, _cancel1_).
1. Let _branch1Stream_ be ! Construct(`<a idl>ReadableStream</a>`, _underlyingSource1_).
1. Let _underlyingSource2_ be ! ObjectCreate(%ObjectPrototype%).
1. Perform ! CreateDataProperty(_underlyingSource2_, `"pull"`, _pull_).
1. Perform ! CreateDataProperty(_underlyingSource2_, `"cancel"`, _cancel2_).
1. Let _branch2Stream_ be ! Construct(`<a idl>ReadableStream</a>`, _underlyingSource2_).
1. Set _pull_.[[branch1]] to _branch1Stream_.[[readableStreamController]].
1. Set _pull_.[[branch2]] to _branch2Stream_.[[readableStreamController]].
1. <a>Upon rejection</a> of _reader_.[[closedPromise]] with reason _r_,
1. If _teeState_.[[closedOrErrored]] is *true*, return *undefined*.
1. Perform ! ReadableStreamDefaultControllerError(_pull_.[[branch1]], _r_).
1. Perform ! ReadableStreamDefaultControllerError(_pull_.[[branch2]], _r_).
1. Set _teeState_.[[closedOrErrored]] to *true*.
1. Return « _branch1Stream_, _branch2Stream_ ».
</emu-alg>
A <dfn>ReadableStreamTee pull function</dfn> is an anonymous built-in function that pulls data from a given <a>readable
stream reader</a> and enqueues it into two other streams ("branches" of the associated tee). Each ReadableStreamTee
pull function has \[[reader]], \[[branch1]], \[[branch2]], \[[teeState]], and \[[cloneForBranch2]] internal slots. When
a ReadableStreamTee pull function <var>F</var> is called, it performs the following steps:
<emu-alg>
1. Let _reader_ be _F_.[[reader]], _branch1_ be _F_.[[branch1]], _branch2_ be _F_.[[branch2]], _teeState_ be
_F_.[[teeState]], and _cloneForBranch2_ be _F_.[[cloneForBranch2]].
1. Return the result of transforming ! ReadableStreamDefaultReaderRead(_reader_) by a fulfillment handler which takes
the argument _result_ and performs the following steps:
1. Assert: Type(_result_) is Object.
1. Let _value_ be ? Get(_result_, `"value"`).
1. Let _done_ be ? Get(_result_, `"done"`).
1. Assert: Type(_done_) is Boolean.
1. If _done_ is *true* and _teeState_.[[closedOrErrored]] is *false*,
1. If _teeState_.[[canceled1]] is *false*,
1. Perform ! ReadableStreamDefaultControllerClose(_branch1_).
1. If _teeState_.[[canceled2]] is *false*,
1. Perform ! ReadableStreamDefaultControllerClose(_branch2_).
1. Set _teeState_.[[closedOrErrored]] to *true*.
1. If _teeState_.[[closedOrErrored]] is *true*, return *undefined*.
1. Let _value1_ and _value2_ be _value_.
1. If _teeState_.[[canceled2]] is *false* and _cloneForBranch2_ is *true*, set _value2_ to ? <a
abstract-op>StructuredClone</a>(_value2_).
1. If _teeState_.[[canceled1]] is *false*, perform ? ReadableStreamDefaultControllerEnqueue(_branch1_, _value1_).
1. If _teeState_.[[canceled2]] is *false*, perform ? ReadableStreamDefaultControllerEnqueue(_branch2_, _value2_).
</emu-alg>
A <dfn>ReadableStreamTee branch 1 cancel function</dfn> is an anonymous built-in function that reacts to the
cancellation of the first of the two branches of the associated tee. Each ReadableStreamTee branch 1 cancel function
has \[[stream]] and \[[teeState]] internal slots. When a ReadableStreamTee branch 1 cancel function <var>F</var> is
called with argument <var>reason</var>, it performs the following steps:
<emu-alg>
1. Let _stream_ be _F_.[[stream]] and _teeState_ be _F_.[[teeState]].
1. Set _teeState_.[[canceled1]] to *true*.
1. Set _teeState_.[[reason1]] to _reason_.
1. If _teeState_.[[canceled2]] is *true*,
1. Let _compositeReason_ be ! CreateArrayFromList(« _teeState_.[[reason1]], _teeState_.[[reason2]] »).
1. Let _cancelResult_ be ! ReadableStreamCancel(_stream_, _compositeReason_).
1. <a>Resolve</a> _teeState_.[[promise]] with _cancelResult_.
1. Return _teeState_.[[promise]].
</emu-alg>
A <dfn>ReadableStreamTee branch 2 cancel function</dfn> is an anonymous built-in function that reacts to the
cancellation of the second of the two branches of the associated tee. Each ReadableStreamTee branch 2 cancel function
has \[[stream]] and \[[teeState]] internal slots. When a ReadableStreamTee branch 2 cancel function <var>F</var> is
called with argument <var>reason</var>, it performs the following steps:
<emu-alg>
1. Let _stream_ be _F_.[[stream]] and _teeState_ be _F_.[[teeState]].
1. Set _teeState_.[[canceled2]] to *true*.
1. Set _teeState_.[[reason2]] to _reason_.
1. If _teeState_.[[canceled1]] is *true*,
1. Let _compositeReason_ be ! CreateArrayFromList(« _teeState_.[[reason1]], _teeState_.[[reason2]] »).
1. Let _cancelResult_ be ! ReadableStreamCancel(_stream_, _compositeReason_).
1. <a>Resolve</a> _teeState_.[[promise]] with _cancelResult_.
1. Return _teeState_.[[promise]].
</emu-alg>
<div class="note">
The algorithm given here is written such that three new function objects are created for each call to to
ReadableStreamTee. This is just a simplification, and is not actually necessary, since it is unobservable to
developer code. For example, a self-hosted implementation could optimize by creating a class whose prototype contains
methods for these functions, with the state stored as instance variables.
</div>
<h3 id="rs-abstract-ops-used-by-controllers">Readable Stream Abstract Operations Used by Controllers</h3>
In terms of specification factoring, the way that the {{ReadableStream}} class encapsulates the behavior of
both simple readable streams and <a>readable byte streams</a> 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 <a>internal queue</a> is managed and how it interfaces with its <a>underlying source</a>
or <a>underlying byte source</a>.
The abstract operations in this section are interfaces that are used by the controller implementations to affect their
associated {{ReadableStream}} object, translating those internal state changes into developer-facing results
visible through the {{ReadableStream}}'s public API.
<h4 id="readable-stream-add-read-into-request" aoid="ReadableStreamAddReadIntoRequest"
nothrow>ReadableStreamAddReadIntoRequest ( <var>stream</var> )</h4>
<emu-alg>
1. Assert: ! IsReadableStreamBYOBReader(_stream_.[[reader]]) is *true*.
1. Assert: _stream_.[[state]] is `"readable"` or `"closed"`.
1. Let _promise_ be <a>a new promise</a>.
1. Let _readIntoRequest_ be Record {[[promise]]: _promise_}.
1. Append _readIntoRequest_ as the last element of _stream_.[[reader]].[[readIntoRequests]].
1. Return _promise_.
</emu-alg>
<h4 id="readable-stream-add-read-request" aoid="ReadableStreamAddReadRequest" nothrow>ReadableStreamAddReadRequest (
<var>stream</var> )</h4>
<emu-alg>
1. Assert: ! IsReadableStreamDefaultReader(_stream_.[[reader]]) is *true*.
1. Assert: _stream_.[[state]] is `"readable"`.
1. Let _promise_ be <a>a new promise</a>.
1. Let _readRequest_ be Record {[[promise]]: _promise_}.
1. Append _readRequest_ as the last element of _stream_.[[reader]].[[readRequests]].
1. Return _promise_.
</emu-alg>
<h4 id="readable-stream-cancel" aoid="ReadableStreamCancel" nothrow export>ReadableStreamCancel ( <var>stream</var>,
<var>reason</var> )</h4>
<emu-alg>
1. Set _stream_.[[disturbed]] to *true*.
1. If _stream_.[[state]] is `"closed"`, return <a>a promise resolved with</a> *undefined*.
1. If _stream_.[[state]] is `"errored"`, return <a>a promise rejected with</a> _stream_.[[storedError]].
1. Perform ! ReadableStreamClose(_stream_).
1. Let _sourceCancelPromise_ be ! _stream_.[[readableStreamController]].[[Cancel]](_reason_).
1. Return the result of transforming _sourceCancelPromise_ by a fulfillment handler that returns *undefined*.
</emu-alg>
<h4 id="readable-stream-close" aoid="ReadableStreamClose" nothrow>ReadableStreamClose ( <var>stream</var> )</h4>
<emu-alg>
1. Assert: _stream_.[[state]] is `"readable"`.
1. Set _stream_.[[state]] to `"closed"`.
1. Let _reader_ be _stream_.[[reader]].
1. If _reader_ is *undefined*, return *undefined*.
1. If ! IsReadableStreamDefaultReader(_reader_) is *true*,
1. Repeat for each _readRequest_ that is an element of _reader_.[[readRequests]],
1. <a>Resolve</a> _readRequest_.[[promise]] with ! CreateIterResultObject(*undefined*, *true*).
1. Set _reader_.[[readRequests]] to an empty List.
1. <a>Resolve</a> _reader_.[[closedPromise]] with *undefined*.
1. Return *undefined*.
</emu-alg>
<div class="note">
The case where <var>stream</var>.\[[state]] is <code>"closed"</code>, but <var>stream</var>.\[[closeRequested]] is
<emu-val>false</emu-val>, will happen if the stream was closed without its controller's close method ever being
called: i.e., if the stream was closed by a call to {{ReadableStream/cancel(reason)}}. In this case we allow the
controller's <code>close</code> method to be called and silently do nothing, since the cancelation was outside the
control of the underlying source.
</div>
<h4 id="readable-stream-error" aoid="ReadableStreamError" nothrow>ReadableStreamError ( <var>stream</var>, <var>e</var>
)</h4>
<emu-alg>
1. Assert: ! IsReadableStream(_stream_) is *true*.
1. Assert: _stream_.[[state]] is `"readable"`.
1. Set _stream_.[[state]] to `"errored"`.
1. Set _stream_.[[storedError]] to _e_.
1. Let _reader_ be _stream_.[[reader]].
1. If _reader_ is *undefined*, return *undefined*.
1. If ! IsReadableStreamDefaultReader(_reader_) is *true*,
1. Repeat for each _readRequest_ that is an element of _reader_.[[readRequests]],
1. <a>Reject</a> _readRequest_.[[promise]] with _e_.
1. Set _reader_.[[readRequests]] to a new empty List.
1. Otherwise,
1. Assert: ! IsReadableStreamBYOBReader(_reader_).
1. Repeat for each _readIntoRequest_ that is an element of _reader_.[[readIntoRequests]],
1. <a>Reject</a> _readIntoRequest_.[[promise]] with _e_.
1. Set _reader_.[[readIntoRequests]] to a new empty List.
1. <a>Reject</a> _reader_.[[closedPromise]] with _e_.
</emu-alg>
<h4 id="readable-stream-fulfill-read-into-request" aoid="ReadableStreamFulfillReadIntoRequest"
nothrow>ReadableStreamFulfillReadIntoRequest ( <var>stream</var>, <var>chunk</var>, <var>done</var> )</h4>
<emu-alg>