Skip to content

Commit fe482f8

Browse files
committed
ReadableStream.prototype.text(), .blob(), and .bytes()
Adds utility methods to akin to the Body mixin for fully reading the contents of a ReadableStream as either text, a Blob, or a Uint8Array.
1 parent 4a2ba76 commit fe482f8

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

index.bs

+120
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,10 @@ interface ReadableStream {
508508
Promise<undefined> pipeTo(WritableStream destination, optional StreamPipeOptions options = {});
509509
sequence<ReadableStream> tee();
510510

511+
Promise<USVString> text(optional ConsumeBytesOptions options = {});
512+
Promise<Uint8Array> bytes(optional ConsumeBytesOptions options = {});
513+
Promise<Blob> blob(optional ConsumeBytesOptions options = {});
514+
511515
async iterable<any>(optional ReadableStreamIteratorOptions options = {});
512516
};
513517

@@ -534,6 +538,11 @@ dictionary StreamPipeOptions {
534538
boolean preventCancel = false;
535539
AbortSignal signal;
536540
};
541+
542+
dictionary ConsumeBytesOptions {
543+
AbortSignal signal;
544+
USVString type = "";
545+
};
537546
</xmp>
538547

539548
<h4 id="rs-internal-slots">Internal slots</h4>
@@ -1014,6 +1023,24 @@ option. If {{UnderlyingSource/type}} is set to undefined (including via omission
10141023
</div>
10151024
</div>
10161025

1026+
<div algorithm>
1027+
The <dfn id="rs-text" method for="ReadableStream">text(options)</div> method steps are:
1028+
1029+
1. Return ? [$ReadableStreamConsumeAsText$]([=this=], |options|).
1030+
</div>
1031+
1032+
<div algorithm>
1033+
The <dfn id="rs-bytes" method for="ReadableStream">bytes(options)</div> method steps are:
1034+
1035+
1. Return ? [$ReadableStreamConsumeAsBytes$]([=this=], |options|).
1036+
</div>
1037+
1038+
<div algorithm>
1039+
The <dfn id="rs-blob" method for="ReadableStream">blob(options)</div> method steps are:
1040+
1041+
1. Return ? [$ReadableStreamConsumeAsBlob$]([=this=], |options|).
1042+
</div>
1043+
10171044
<h4 id="rs-asynciterator" oldids="rs-asynciterator-prototype,
10181045
default-reader-asynciterator-prototype-internal-slots">Asynchronous iteration</h4>
10191046
@@ -2661,6 +2688,99 @@ create them does not matter.
26612688
1. Return « |branch1|, |branch2| ».
26622689
</div>
26632690

2691+
<div algorithm>
2692+
To <dfn lt="fully read">fully read</dfn> a {{ReadableStream}} |stream|, given an algorithm |processBody|, and an algorithm |processBodyError|, run these steps. |processBody| must be an algorithm accepting a [=byte sequence=]. |processBodyError| must be an algorithm optionally accepting an exception.
2693+
2694+
1. Let |successSteps| given a [=byte sequence=] |bytes| be to run |processBody| given |bytes|.
2695+
1. Let |errorSteps| optionally given an exception |exception| be to run |processBodyError| given |exception|.
2696+
1. Let |reader| be the result of getting a reader for |stream|. If that threw an exception, then run |errorSteps| with that exception and return.
2697+
1. [=read all bytes|Read all bytes=] from |reader|, given |successSteps| and |errorSteps|.
2698+
</div>
2699+
2700+
<div algorithm>
2701+
The <dfn lt="consume fully with abort">consume fully with abort</dfn> algorithm, given a {{ReadableStream}} |stream|, an optional {{AbortSignal}} |signal|, and an algorithm that takes a [=byte sequence=] and returns a JavaScript or throws an exception |convertBytesToJSValue|, runs these steps:
2702+
2703+
1. Let |promise| be [=a new promise=].
2704+
1. Let |errorSteps| given |error| to be [=reject=] |promise| with |error|.
2705+
1. Let |successSteps| given a [=byte sequence=] |data| be to [=resolve=] |promise| with the result of running |convertBytesToJSValue| with |data|. If that threw an exception, then run |errorSteps| with that exception.
2706+
1. If |signal| is not undefined,
2707+
1. Let |abortAlgorithm| be the following steps:
2708+
1. Let |error| be |signal|'s [=AbortSignal/abort reason=].
2709+
1. Run |errorSteps| with |error|.
2710+
1. Let |actions| be an empty [=ordered set=].
2711+
1. If |stream|.[=ReadableStream/[[state]]=] is "`readable`", [=set/append=] the following action action to |actions|:
2712+
1. return ! [$ReadableStreamCancel$](|stream|, |error|).
2713+
1. Otherwise, return [=a promise resolved with=] undefined.
2714+
1. [=Shutdown with an action=] consisting of [=getting a promise to wait for all=] of the actions
2715+
in |actions|, and with |error|.
2716+
1. If |signal| is [=AbortSignal/aborted=], perform the following steps:
2717+
1. perform |abortAlgorithm|.
2718+
1. return |promise|.
2719+
1. [=AbortSignal/Add=] |abortAlgorithm| to |signal|.
2720+
1. [=fully read=] |stream| given |successSteps|, |errorSteps|, and |stream|’s relevant global object.
2721+
1. Return promise.
2722+
</div>
2723+
2724+
<div algorithm>
2725+
<dfn abstract-op lt="ReadableStreamConsumeAsText" id="ReadableStreamConsumeAsText">ReadableStreamConsumeAsText(|stream|, |options|})</dfn> will
2726+
consume all bytes produced by a given readable stream and return a promise that resolves with a string containing the UTF-8-decoded text.
2727+
2728+
It performs the following steps:
2729+
2730+
1. Assert: |stream| [=implements=] {{ReadableStream}}.
2731+
1. If ! [$IsReadableStreamLocked$]([=stream=]) is true, return [=a promise rejected with=] a
2732+
{{TypeError}} exception.
2733+
1. If ! |stream|.[=ReadableStream/[[disturbed]]=] is true, return [=a promise rejected with=] a
2734+
{{TypeError}} exception.
2735+
1. Let |signal| be |options|["{{ConsumeBytesOptions/signal}}"] if it [=map/exists=], or undefined
2736+
otherwise.
2737+
1. Assert: either |signal| is undefined, or |signal| [=implements=] {{AbortSignal}}.
2738+
1. Return the result of running [=consume fully with abort=] with |stream|, |signal|, and <a>UTF-8 decode</a>.
2739+
</div>
2740+
2741+
<div algorithm>
2742+
<dfn abstract-op lt="ReadableStreamConsumeAsBytes" id="ReadableStreamConsumeAsBytes">ReadableStreamConsumeAsBytes(|stream|, |options|})</dfn> will
2743+
consume all bytes produced by a given readable stream and return a promise that resolves with a single Uint8Array containing the read bytes.
2744+
2745+
It performs the following steps:
2746+
2747+
1. Assert: |stream| [=implements=] {{ReadableStream}}.
2748+
1. If ! [$IsReadableStreamLocked$]([=stream=]) is true, return [=a promise rejected with=] a
2749+
{{TypeError}} exception.
2750+
1. If ! |stream|.[=ReadableStream/[[disturbed]]=] is true, return [=a promise rejected with=] a
2751+
{{TypeError}} exception.
2752+
1. Let |signal| be |options|["{{ConsumeBytesOptions/signal}}"] if it [=map/exists=], or undefined
2753+
otherwise.
2754+
1. Assert: either |signal| is undefined, or |signal| [=implements=] {{AbortSignal}}.
2755+
1. Let |decode as Uint8Array| be an algorithm that takes a [=byte sequence=] |bytes| and runs the steps:
2756+
1. Let |arrayBuffer| be a new {{ArrayBuffer}} whose contents are |bytes|.
2757+
1. Let |view| be the result of [=ArrayBufferView/create|creating=] a {{Uint8Array}} from |arrayBuffer|.
2758+
1. Return |view|.
2759+
1. Return the result of running [=consume fully with abort=] with |stream|, |signal|, and |decode as Uint8Array|.
2760+
</div>
2761+
2762+
<div algorithm>
2763+
<dfn abstract-op lt="ReadableStreamConsumeAsBlob" id="ReadableStreamConsumeAsBlob">ReadableStreamConsumeAsBlob(|stream|, |options|})</dfn> will
2764+
consume all bytes produced by a given readable stream and return a promise that resolves with a Blob.
2765+
2766+
It performs the following steps:
2767+
2768+
1. Assert: |stream| [=implements=] {{ReadableStream}}.
2769+
1. If ! [$IsReadableStreamLocked$]([=stream=]) is true, return [=a promise rejected with=] a
2770+
{{TypeError}} exception.
2771+
1. If ! |stream|.[=ReadableStream/[[disturbed]]=] is true, return [=a promise rejected with=] a
2772+
{{TypeError}} exception.
2773+
1. Let |signal| be |options|["{{ConsumeBytesOptions/signal}}"] if it [=map/exists=], or undefined
2774+
otherwise.
2775+
1. Let |type| be |options|["{{ConsumeBytesOptions/type}}"] if it [=map/exists=], or an empty string
2776+
otherwise.
2777+
1. Assert: either |signal| is undefined, or |signal| [=implements=] {{AbortSignal}}.
2778+
1. Let |decode as Blob| be an algorithm that takes a [=byte sequence=] |bytes| and a string |type| and runs the steps:
2779+
1. Let |blob| be a new {{Blob}} whose contents are |bytes| and whose {{Blob/type}} attribute is |type|.
2780+
1. Return |blob|.
2781+
1. Return the result of running [=consume fully with abort=] with |stream|, |signal|, and |decode as Blob|.
2782+
</div>
2783+
26642784
<h4 id="rs-abstract-ops-used-by-controllers">Interfacing with controllers</h4>
26652785

26662786
In terms of specification factoring, the way that the {{ReadableStream}} class encapsulates the

0 commit comments

Comments
 (0)