-
Notifications
You must be signed in to change notification settings - Fork 161
/
index.bs
3397 lines (2770 loc) · 155 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
Status: LS
Editor: Domenic Denicola, Google https://www.google.com/, d@domenic.me, https://domenic.me/
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
!Participate: <a href="https://github.com/whatwg/streams/issues/new">File an issue</a> (<a href="https://github.com/whatwg/streams/issues?state=open">open issues</a>)
!Participate: <a href="https://wiki.whatwg.org/wiki/IRC">IRC: #whatwg on Freenode</a>
!Version History: <a href="https://github.com/whatwg/streams/commits">https://github.com/whatwg/streams/commits</a>
!Version History: [SNAPSHOT-LINK]
!Version History: <a href="https://twitter.com/streamsstandard">@streamsstandard</a>
Link Defaults: html (dfn) structured clone
</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; }
</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 a 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 <code>Uint8Array</code>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.
<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 writen 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">
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>
<!-- TODO: writable streams too, probably -->
A <dfn>readable stream reader</dfn> (<dfn>readable byte stream reader</dfn> or
<dfn>readable byte stream byob reader</dfn> for <a>readable byte stream</a>) 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: waiting for the stream to become closed or errored,
<a lt="cancel a readable stream">canceling</a> the stream, or <a>piping</a> the readable stream to a writable stream.
Many of those high-level operations actually use a reader themselves.
A given readable stream only has at most one reader at a time. We say in this case the stream is
<dfn lt="locked to a reader">locked to the reader</dfn>, and that the reader is <dfn lt="active reader">active</dfn>.
A reader also has the capability to <dfn lt="release a read lock">release its read lock</dfn>, which makes it no
longer active. At this point another reader can be acquired at will. If the stream becomes closed or errored as a
result of the behavior of its <a>underlying source</a> or via <a lt="cancel a readable stream">cancellation</a>, its
reader (if one exists) will automatically release its lock.
<h3 id="byte-streams">Readable Byte Streams</h3>
For streams representing bytes, an extended version of the readable stream is provided to handle bytes efficiently.
A <dfn>readable byte stream</dfn> represents a source of bytes, from which you can read.
Although a readable byte stream can be created with arbitrary behavior, most readable byte streams wrap a lower-level
I/O source, called the <dfn>underlying byte source</dfn>.
<h2 id="rs">Readable Streams</h2>
<h3 id="rs-intro">Using Readable Streams</h3>
<div class="example">
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">
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>
</div>
<h3 id="rs-class">Class <code>ReadableStream</code></h3>
The <code>ReadableStream</code> 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 <code>ReadableStream</code> class in something close to the syntax of [[!ECMASCRIPT]], it
would look like
<pre><code class="lang-javascript">
class ReadableStream {
constructor(underlyingSource = {}, { size, highWaterMark = 1 } = {})
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 <code>ReadableStream</code> 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>\[[closeRequested]]
<td>A boolean flag indicating whether the stream has been closed by its <a>underlying source</a>, but still has
<a>chunks</a> in its internal queue that have not yet been read
</tr>
<tr>
<td>\[[controller]]
<td>A <a href="#rs-controller-class"><code>ReadableStreamController</code></a> created with the ability to control the
state and queue of this stream
</tr>
<tr>
<td>\[[pullAgain]]
<td>A boolean flag set to <b>true</b> if the stream's mechanisms requested a call to the underlying source's
<code>pull</code> method to pull more data, but the pull could not yet be done since a previous call is still
executing
</tr>
<tr>
<td>\[[pulling]]
<td>A boolean flag set to <b>true</b> while the underlying source's <code>pull</code> method is executing and has
not yet fulfilled, used to prevent reentrant calls
</tr>
<tr>
<td>\[[queue]]
<td>A List representing the stream's internal queue of <a>chunks</a>
</tr>
<tr>
<td>\[[reader]]
<td>A <a href="#reader-class"><code>ReadableStreamReader</code></a> instance, if the stream is <a>locked to a
reader</a>, or <b>undefined</b> if it is not
</tr>
<tr>
<td>\[[started]]
<td>A boolean flag indicating whether the <a>underlying source</a> has finished starting
</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>
<tr>
<td>\[[strategySize]]
<td>A function supplied to the constructor as part of the stream's <a>queuing strategy</a>, designed to calculate
the size of enqueued <a>chunks</a>; can be <b>undefined</b> for the default behavior.
</tr>
<tr>
<td>\[[strategyHWM]]
<td>A number supplied to the constructor as part of the stream's <a>queuing strategy</a>, indicating the point at
which the stream will apply <a>backpressure</a> to its <a>underlying source</a>.
</tr>
<tr>
<td>\[[underlyingSource]]
<td>An object representation of the stream's <a>underlying source</a>, including its <a>queuing strategy</a>; also
used for the <a href="#is-readable-stream">IsReadableStream</a> brand check
</tr>
</table>
<h4 id="rs-constructor">new ReadableStream(underlyingSource = {}, { size, highWaterMark = 1 } = {})</h4>
<div class="note">
The <var>underlyingSource</var> 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 internal queue of chunks is depleted, and the
consumer has signaled that they wish to consume more data. 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, which is an instance of
<a href="#rs-controller-class"><code>ReadableStreamController</code></a>. This is an example of the
<a href="https://blog.domenic.me/the-revealing-constructor-pattern/">revealing constructor pattern</a>.
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 <code>CountQueuingStrategy</code> or
<code>ByteLengthQueuingStrategy</code> classes, or it could be custom. If no strategy is supplied, the default
behavior will be the same as a <code>CountQueuingStrategy</code> with a <a>high water mark</a> of 1.
</div>
<pre is="emu-alg">
1. Set *this*@[[underlyingSource]] to _underlyingSource_.
1. Set *this*@[[queue]] to a new empty List.
1. Set *this*@[[state]] to "readable".
1. Set *this*@[[started]], *this*@[[closeRequested]], *this*@[[pullAgain]], and *this*@[[pulling]] to *false*.
1. Set *this*@[[reader]] and *this*@[[storedError]] to *undefined*.
1. Set *this*@[[controller]] to Construct(`ReadableStreamController`, «*this*»).
1. Let _normalizedStrategy_ be ValidateAndNormalizeQueuingStrategy(_size_, _highWaterMark_).
1. Set *this*@[[strategySize]] to _normalizedStrategy_.[[size]] and *this*@[[strategyHWM]] to _normalizedStrategy_.[[highWaterMark]].
1. Let _startResult_ be InvokeOrNoop(_underlyingSource_, "start", «*this*@[[controller]]»).
1. ReturnIfAbrupt(_startResult_).
1. Resolve _startResult_ as a promise:
1. Upon fulfillment,
1. Set *this*@[[started]] to *true*.
1. Return RequestReadableStreamPull(*this*).
1. Upon rejection with reason _r_,
1. If *this*@[[state]] is "readable", return ErrorReadableStream(*this*, _r_).
</pre>
<h4 id="rs-prototype">Properties of the <code>ReadableStream</code> Prototype</h4>
<h5 id="rs-cancel">cancel(reason)</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 <var>reason</var> argument will be given to the underlying source, which
may or may not use it.
</div>
<pre is="emu-alg">
1. If IsReadableStream(*this*) is *false*, return a promise rejected with a *TypeError* exception.
1. If IsReadableStreamLocked(*this*) is *true*, return a promise rejected with a *TypeError* exception.
1. Return CancelReadableStream(*this*, _reason_).
</pre>
<h5 id="rs-get-reader">getReader()</h5>
<div class="note">
The <code>getReader</code> method creates a <a>readable stream reader</a> 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>. The returned reader provides the ability
to directly read individual <a>chunks</a> from the stream via the reader's <code>read</code> method.
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.
Note that if a stream becomes closed or errored, any reader it is locked to is automatically released.
</div>
<pre is="emu-alg">
1. If IsReadableStream(*this*) is *false*, throw a *TypeError* exception.
1. Return AcquireReadableStreamReader(*this*).
</pre>
<div class="example">
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">pipeThrough({ writable, readable }, options)</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 <b>this</b> value be a <code>ReadableStream</code>
object. It also does not require that its <code>writable</code> argument be a <code>WritableStream</code> instance,
or that its <code>readable</code> argument be a <code>ReadableStream</code> instance.
</div>
<pre is="emu-alg">
1. Call-with-rethrow Invoke(*this*, "pipeTo", «_writable_, _options_»).
1. Return _readable_.
</pre>
<div class="example">
A typical example of constructing <a>pipe chain</a> using <code>pipeThrough</code> would look like
<pre><code class="lang-javascript">
httpResponseBody
.pipeThrough(decompressorTransform)
.pipeThrough(ignoreNonImageFilesTransform)
.pipeTo(mediaGallery);
</code></pre>
</div>
<h5 id="rs-pipe-to">pipeTo(dest, { preventClose, preventAbort, preventCancel } = {})</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 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 <b>this</b> value be a <code>ReadableStream</code>
object.
</div>
The <code>pipeTo</code> method is one of the more complex methods, and is undergoing some revision and edge-case
bulletproofing before we write it up in prose.
For now, please consider the reference implementation normative:
<a href="https://github.com/whatwg/streams/blob/master/reference-implementation/lib/readable-stream.js">reference-implementation/lib/readable-stream.js</a>,
look for the <code>pipeTo</code> method.
<h5 id="rs-tee">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 <code>ReadableStream</code> 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>structured clones</a> of the chunks for each
branch.)
</div>
<pre is="emu-alg">
1. If IsReadableStream(*this*) is *false*, throw a *TypeError* exception.
1. Let _branches_ be TeeReadableStream(*this*, *false*).
1. ReturnIfAbrupt(_branches_).
1. Return CreateArrayFromList(_branches_).
</pre>
<div class="example">
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-controller-class" lt="ReadableStreamController">Class <code>ReadableStreamController</code></h3>
The <code>ReadableStreamController</code> class has methods that allow control of a <code>ReadableStream</code>'s state
and <a>internal queue</a>. When constructing a <code>ReadableStream</code>, the <a>underlying source</a> is given a
corresponding <code>ReadableStreamController</code> instance to manipulate.
<h4 id="rs-controller-class-definition">Class Definition</h4>
<em>This section is non-normative.</em>
If one were to write the <code>ReadableStreamController</code> class in something close to the syntax of [[!ECMASCRIPT]],
it would look like
<pre><code class="lang-javascript">
class ReadableStreamController {
constructor(stream)
get desiredSize()
close()
enqueue(chunk)
error(e)
}
</code></pre>
<h4 id="rs-controller-internal-slots">Internal Slots</h4>
Instances of <code>ReadableStreamController</code> 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>\[[controlledReadableStream]]
<td>The <code>ReadableStream</code> instance controlled
</tr>
</table>
<h4 id="rs-controller-constructor">new ReadableStreamController(stream)</h4>
<div class="note">
The <code>ReadableStreamController</code> constructor cannot be used directly; it only works on a
<code>ReadableStream</code> that is in the middle of being constructed.
</div>
<pre is="emu-alg">
1. If IsReadableStream(_stream_) is *false*, throw a *TypeError* exception.
1. If _stream_@[[controller]] is not *undefined*, throw a *TypeError* exception.
1. Set *this*@[[controlledReadableStream]] to _stream_.
</pre>
<h4 id="rs-controller-prototype">Properties of the <code>ReadableStreamController</code> Prototype</h4>
<h5 id="rs-controller-desired-size">get desiredSize</h5>
<div class="note">
The <code>desiredSize</code> getter returns the <a lt="desired size to fill a stream's internal queue">desired size
to fill the controlled stream's internal queue</a>. It can be negative, if the queue is over-full. An <a>underlying
source</a> should use this information to determine when and how to apply <a>backpressure</a>.
</div>
<pre is="emu-alg">
1. If IsReadableStreamController(*this*) is *false*, throw a *TypeError* exception.
1. Return GetReadableStreamDesiredSize(*this*@[[controlledReadableStream]]).
</pre>
<h5 id="rs-controller-close">close()</h5>
<div class="note">
The <code>close</code> method will close the controlled readable stream. <a>Consumers</a> will still be able to read
any previously-enqueued <a>chunks</a> from the stream, but once those are read, the stream will become closed.
</div>
<pre is="emu-alg">
1. If IsReadableStreamController(*this*) is *false*, throw a *TypeError* exception.
1. Let _stream_ be *this*@[[controlledReadableStream]].
1. If _stream_@[[closeRequested]] is *true*, throw a *TypeError* exception.
1. If _stream_@[[state]] is "errored", throw a *TypeError* exception.
1. Return CloseReadableStream(_stream_).
</pre>
<h5 id="rs-controller-enqueue">enqueue(chunk)</h5>
<div class="note">
The <code>enqueue</code> method will enqueue a given <a>chunk</a> in the controlled readable stream.
</div>
<pre is="emu-alg">
1. If IsReadableStreamController(*this*) is *false*, throw a *TypeError* exception.
1. Let _stream_ be *this*@[[controlledReadableStream]].
1. If _stream_@[[state]] is "errored", throw _stream_@[[storedError]].
1. If _stream_@[[closeRequested]] is *true*, throw a *TypeError* exception.
1. Return EnqueueInReadableStream(_stream_, _chunk_).
</pre>
<h5 id="rs-controller-error">error(e)</h5>
<div class="note">
The <code>error</code> method will error the readable stream, making all future interactions with it fail with the
given error <var>e</var>.
</div>
<pre is="emu-alg">
1. If IsReadableStreamController(*this*) is *false*, throw a *TypeError* exception.
1. If *this*@[[controlledReadableStream]]@[[state]] is not "readable", throw a *TypeError* exception.
1. Return ErrorReadableStream(*this*@[[controlledReadableStream]]).
</pre>
<h3 id="reader-class">Class <code>ReadableStreamReader</code></h3>
The <code>ReadableStreamReader</code> class represents a <a>readable stream reader</a> designed to be vended by a
<code>ReadableStream</code> instance.
<h4 id="reader-class-definition">Class Definition</h4>
<em>This section is non-normative.</em>
If one were to write the <code>ReadableStreamReader</code> class in something close to the syntax of [[!ECMASCRIPT]],
it would look like
<pre><code class="lang-javascript">
class ReadableStreamReader {
constructor(stream)
get closed()
cancel(reason)
read()
releaseLock()
}
</code></pre>
<h4 id="reader-internal-slots">Internal Slots</h4>
Instances of <code>ReadableStreamReader</code> 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>\[[closedPromise]]
<td>A promise returned by the reader's <code>closed</code> getter
</tr>
<tr>
<td>\[[ownerReadableStream]]
<td>A <code>ReadableStream</code> instance that owns this reader; also used for the
<a href="#is-readable-stream-reader">IsReadableStreamReader</a> brand check
</tr>
<tr>
<td>\[[readRequests]]
<td>A List of promises returned by calls to the reader's <code>read()</code> method that have not yet been resolved,
due to the <a>consumer</a> requesting <a>chunks</a> sooner than they are available
</tr>
<tr>
<td>\[[state]]
<td>A string containing the reader'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 reader's stream failed, to be given as a failure reason or exception when trying to
operate on the reader; applicable only when \[[state]] is <code>"errored"</code>
</tr>
</table>
<h4 id="reader-constructor">new ReadableStreamReader(stream)</h4>
<div class="note">
The <code>ReadableStreamReader</code> constructor is generally not meant to be used directly; instead, a stream's
<code>getReader()</code> method should be used. This allows different classes of readable streams to vend different
classes of readers without the <a>consumer</a> needing to know which goes with which.
</div>
<pre is="emu-alg">
1. If IsReadableStream(_stream_) is *false*, throw a *TypeError* exception.
1. If IsReadableStreamLocked(_stream_) is *true*, throw a *TypeError* exception.
1. Set _stream_@[[reader]] to *this*.
1. Set *this*@[[ownerReadableStream]] to _stream_.
1. Set *this*@[[state]] to "readable".
1. Set *this*@[[storedError]] to *undefined*.
1. Set *this*@[[readRequests]] to a new empty List.
1. Set *this*@[[closedPromise]] to a new promise.
1. If _stream_@[[state]] is "closed" or "errored", call-with-rethrow ReleaseReadableStreamReader(*this*).
</pre>
<h4 id="reader-prototype">Properties of the <code>ReadableStreamReader</code> Prototype</h4>
<h5 id="reader-closed">get closed</h5>
<div class="note">
The <code>closed</code> getter returns a promise that will be fulfilled when the stream becomes closed or the
reader's lock is <a lt="release a read lock">released</a>, or rejected if the stream ever errors.
</div>
<pre is="emu-alg">
1. If IsReadableStreamReader(*this*) is *false*, return a promise rejected with a *TypeError* exception.
1. Return *this*@[[closedPromise]].
</pre>
<h5 id="reader-cancel">cancel(reason)</h5>
<div class="note">
If the reader is <a lt="active reader">active</a>, the <code>cancel</code> method behaves the same as that for the
associated stream. When done, it automatically <a lt="release a read lock">releases the lock</a>.
</div>
<pre is="emu-alg">
1. If IsReadableStreamReader(*this*) is *false*, return a promise rejected with a *TypeError* exception.
1. If *this*@[[state]] is "closed", return a new promise resolved with *undefined*.
1. If *this*@[[state]] is "errored", return a new promise rejected with *this*@[[storedError]].
1. Assert: *this*@[[ownerReadableStream]] is not *undefined*.
1. Assert: *this*@[[ownerReadableStream]]@[[state]] is "readable".
1. Return CancelReadableStream(*this*@[[ownerReadableStream]], _reason_).
</pre>
<h5 id="reader-read">read()</h5>
<div class="note">
The <code>read</code> method will return a promise that allows access to the next <a>chunk</a> from the stream's
internal queue, if available.
<ul>
<li> If the chunk does become available, the promise will be fulfilled with an object of the form
<code>{ value: theChunk, done: false }</code>.
<li> If the stream becomes closed, the promise will be fulfilled with an object of the form
<code>{ value: undefined, done: true }</code>.
<li> If the stream becomes errored, the promise will be rejected with the relevant error.
</ul>
If reading a chunk causes the queue to become empty, more data will be pulled from the <a>underlying source</a>.
</div>
<pre is="emu-alg">
1. If IsReadableStreamReader(*this*) is *false*, return a promise rejected with a *TypeError* exception.
1. Return ReadFromReadableStreamReader(*this*).
</pre>
<h5 id="reader-release-lock">releaseLock()</h5>
<div class="note">
The <code>releaseLock</code> method <a lt="release a read lock">releases the reader's lock</a> on the corresponding
stream. After the lock is released, the reader is no longer <a lt="active reader">active</a>. 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 <code>read()</code> method has not yet been settled. Attempting to do so will throw a <b>TypeError</b>
and leave the reader locked to the stream.
</div>
<pre is="emu-alg">
1. If IsReadableStreamReader(*this*) is *false*, throw a *TypeError* exception.
1. If *this*@[[ownerReadableStream]] is *undefined*, return *undefined*.
1. If *this*@[[readRequests]] is not empty, throw a *TypeError* exception.
1. Return ReleaseReadableStreamReader(*this*).
</pre>
<h3 id="rs-abstract-ops">Readable Stream Abstract Operations</h3>
<h4 id="acquire-readable-stream-reader" aoid="AcquireReadableStreamReader">AcquireReadableStreamReader ( stream )</h4>
This abstract operation is meant to be called from other specifications that may wish to acquire an <a>readable stream
reader</a> for a given stream.
<pre is="emu-alg">
1. Return Construct(`ReadableStreamReader`, «_stream_»).
</pre>
<h4 id="cancel-readable-stream" aoid="CancelReadableStream">CancelReadableStream ( stream, reason )</h4>
<pre is="emu-alg">
1. If _stream_@[[state]] is "closed", return a new promise resolved with *undefined*.
1. If _stream_@[[state]] is "errored", return a new promise rejected with _stream_@[[storedError]].
1. Set _stream_@[[queue]] to a new empty List.
1. Call-with-rethrow FinishClosingReadableStream(_stream_).
1. Let _sourceCancelPromise_ be PromiseInvokeOrNoop(_stream_@[[underlyingSource]], "cancel", «_reason_»).
1. Return the result of transforming _sourceCancelPromise_ by a fulfillment handler that returns *undefined*.
</pre>
<h4 id="close-readable-stream" aoid="CloseReadableStream">CloseReadableStream ( stream )</h4>
This abstract operation can be called by other specifications that wish to close a readable stream, in the same way
a developer-created stream would be closed by its associated controller object. Specifications should <em>not</em> do
this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as asserts).
<pre is="emu-alg">
1. Assert: _stream_@[[closeRequested]] is *false*.
1. Assert: _stream_@[[state]] is not "errored".
1. If _stream_@[[state]] is "closed", return *undefined*.
1. Set _stream_@[[closeRequested]] to *true*.
1. If _stream_@[[queue]] is empty, return FinishClosingReadableStream(_stream_).
</pre>
<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 <code>stream.cancel()</code>. 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="finish-closing-readable-stream" aoid="FinishClosingReadableStream">FinishClosingReadableStream ( stream )</h4>
<pre is="emu-alg">
1. Assert: _stream_@[[state]] is "readable".
1. Set _stream_@[[state]] to "closed".
1. If IsReadableStreamLocked(_stream_) is *true*, return ReleaseReadableStreamReader(_stream_@[[reader]]).
1. Return *undefined*.
</pre>
<h4 id="enqueue-in-readable-stream" aoid="EnqueueInReadableStream">EnqueueInReadableStream ( stream, chunk )</h4>
This abstract operation can be called by other specifications that wish to enqueue <a>chunks</a> in a readable stream,
in the same way a developer would enqueue chunks using the stream's associated controller object. Specifications should
<em>not</em> do this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as
asserts).
<pre is="emu-alg">
1. Assert: _stream_@[[closeRequested]] is *false*.
1. Assert: _stream_@[[state]] is not "errored".
1. If _stream_@[[state]] is "closed", return *undefined*.
1. If IsReadableStreamLocked(_stream_) is *true* and _stream_@[[reader]]@[[readRequests]] is not empty,
1. Let _readRequestPromise_ be the first element of _stream_@[[reader]]@[[readRequests]].
1. Remove _readRequestPromise_ from _stream_@[[reader]]@[[readRequests]], shifting all other elements downward (so that the second becomes the first, and so on).
1. Resolve _readRequestPromise_ with CreateIterResultObject(_chunk_, *false*).
1. Otherwise,
1. Let _chunkSize_ be *1*.
1. If _stream_@[[strategySize]] is not *undefined*,
1. Set _chunkSize_ to Call(_stream_@[[strategySize]], *undefined*, «_chunk_»).
1. If _chunkSize_ is an abrupt completion,
1. Call-with-rethrow ErrorReadableStream(_stream_, _chunkSize_.[[value]]).
1. Return _chunkSize_.
1. Let _chunkSize_ be _chunkSize_.[[value]].
1. Let _enqueueResult_ be EnqueueValueWithSize(_stream_@[[queue]], _chunk_, _chunkSize_).
1. If _enqueueResult_ is an abrupt completion,
1. Call-with-rethrow ErrorReadableStream(_stream_, _enqueueResult_.[[value]]).
1. Return _enqueueResult_.
1. Call-with-rethrow RequestReadableStreamPull(_stream_).
1. Return *undefined*.
</pre>
<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 <code>stream.cancel()</code>. In this case we allow the
controller's <code>enqueue</code> method to be called and silently do nothing, since the cancelation was outside the
control of the underlying source.
</div>
<h4 id="error-readable-stream" aoid="ErrorReadableStream">ErrorReadableStream ( stream, e )</h4>
This abstract operation can be called by other specifications that wish to move a readable stream to an errored state,
in the same way a developer would error a stream using its associated controller object. Specifications should
<em>not</em> do this to streams they did not create, and must ensure they have obeyed the precondition (listed here as
an assert).
<pre is="emu-alg">
1. Assert: _stream_@[[state]] is "readable".
1. Let _stream_@[[queue]] be a new empty List.
1. Set _stream_@[[storedError]] to _e_.
1. Set _stream_@[[state]] to "errored".
1. If IsReadableStreamLocked(_stream_) is *true*, return ReleaseReadableStreamReader(_stream_@[[reader]]).
</pre>
<h4 id="get-readable-stream-desired-size" aoid="GetReadableStreamDesiredSize">GetReadableStreamDesiredSize ( stream )</h4>
<pre is="emu-alg">
1. Let _queueSize_ be GetTotalQueueSize(_stream_@[[queue]]).
1. ReturnIfAbrupt(_queueSize_).
1. Return _stream_@[[strategyHWM]] − _queueSize_.
</pre>
<h4 id="is-readable-stream" aoid="IsReadableStream">IsReadableStream ( x )</h4>
<pre is="emu-alg">
1. If Type(_x_) is not Object, return *false*.
1. If _x_ does not have a [[underlyingSource]] internal slot, return *false*.
1. Return *true*.
</pre>
<h4 id="is-readable-stream-controller" aoid="IsReadableStreamController">IsReadableStreamController ( x )</h4>
<pre is="emu-alg">
1. If Type(_x_) is not Object, return *false*.
1. If _x_ does not have a [[controlledReadableStream]] internal slot, return *false*.
1. Return *true*.
</pre>
<h4 id="is-readable-stream-locked" aoid="IsReadableStreamLocked">IsReadableStreamLocked ( stream )</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>.
<pre is="emu-alg">
1. Assert: IsReadableStream(_stream_) is *true*.
1. If _stream_@[[reader]] is *undefined*, return *false*.
1. Return *true*.
</pre>
<h4 id="is-readable-stream-reader" aoid="IsReadableStreamReader">IsReadableStreamReader ( x )</h4>
<pre is="emu-alg">
1. If Type(_x_) is not Object, return *false*.
1. If _x_ does not have an [[ownerReadableStream]] internal slot, return *false*.
1. Return *true*.
</pre>
<h4 id="read-from-readable-stream-reader" aoid="ReadFromReadableStreamReader">ReadFromReadableStreamReader ( reader )</h4>
<pre is="emu-alg">
1. If _reader_@[[state]] is "closed", return a new promise resolved with CreateIterResultObject(*undefined*, *true*).
1. If _reader_@[[state]] is "errored", return a new promise rejected with _reader_@[[storedError]].
1. Assert: _reader_@[[ownerReadableStream]] is not *undefined*.
1. Assert: _reader_@[[ownerReadableStream]]@[[state]] is "readable".
1. If _reader_@[[ownerReadableStream]]@[[queue]] is not empty,
1. Let _chunk_ be DequeueValue(_reader_@[[ownerReadableStream]]@[[queue]]).
1. If _reader_@[[ownerReadableStream]]@[[closeRequested]] is *true* and _reader_@[[ownerReadableStream]]@[[queue]] is now empty, call-with-rethrow FinishClosingReadableStream(_reader_@[[ownerReadableStream]]).
1. Otherwise, call-with-rethrow RequestReadableStreamPull(_reader_@[[ownerReadableStream]]).
1. Return a new promise resolved with CreateIterResultObject(_chunk_, *false*).
1. Otherwise,
1. Let _readRequestPromise_ be a new promise.
1. Append _readRequestPromise_ as the last element of _reader_@[[readRequests]].
1. Call-with-rethrow RequestReadableStreamPull(_reader_@[[ownerReadableStream]]).
1. Return _readRequestPromise_.
</pre>
<h4 id="release-readable-stream-reader" aoid="ReleaseReadableStreamReader">ReleaseReadableStreamReader ( reader )</h4>
<pre is="emu-alg">
1. Assert: _reader_@[[ownerReadableStream]] is not *undefined*.
1. If _reader_@[[ownerReadableStream]]@[[state]] is "errored",
1. Set _reader_@[[state]] to "errored".
1. Let _e_ be _reader_@[[ownerReadableStream]]@[[storedError]].
1. Set _reader_@[[storedError]] to _e_.
1. Reject _reader_@[[closedPromise]] with _e_.