summaryrefslogtreecommitdiff
path: root/ext/web/06_streams.js
diff options
context:
space:
mode:
authorMarcos Casagrande <marcoscvp90@gmail.com>2023-01-09 21:17:36 +0100
committerGitHub <noreply@github.com>2023-01-09 21:17:36 +0100
commit45768f0e832e54d61ddb5a62d62239aef0e597b5 (patch)
treee9124a28036e082170fe4a0083e7b74be54e8503 /ext/web/06_streams.js
parente6c49d14b1ea6331d2e13f7a0b74a0e41c142596 (diff)
fix(ext/web/streams): fix ReadableStream asyncIterator (#16276)
Diffstat (limited to 'ext/web/06_streams.js')
-rw-r--r--ext/web/06_streams.js117
1 files changed, 80 insertions, 37 deletions
diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js
index 81d97218a..22baa1234 100644
--- a/ext/web/06_streams.js
+++ b/ext/web/06_streams.js
@@ -32,6 +32,7 @@
ObjectDefineProperties,
ObjectDefineProperty,
ObjectGetPrototypeOf,
+ ObjectPrototype,
ObjectPrototypeIsPrototypeOf,
ObjectSetPrototypeOf,
Promise,
@@ -4424,7 +4425,7 @@
* @returns {IteratorResult<T>}
*/
function createIteratorResult(value, done) {
- const result = ObjectCreate(null);
+ const result = ObjectCreate(ObjectPrototype);
ObjectDefineProperties(result, {
value: { value, writable: true, enumerable: true, configurable: true },
done: {
@@ -4442,57 +4443,99 @@
ObjectGetPrototypeOf(async function* () {}).prototype,
);
+ const _iteratorNext = Symbol("[[iteratorNext]]");
+ const _iteratorFinished = Symbol("[[iteratorFinished]]");
+
/** @type {AsyncIterator<unknown>} */
const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({
/** @returns {Promise<IteratorResult<unknown>>} */
next() {
/** @type {ReadableStreamDefaultReader} */
const reader = this[_reader];
- if (reader[_stream] === undefined) {
- return PromiseReject(
- new TypeError(
- "Cannot get the next iteration result once the reader has been released.",
- ),
- );
+ function nextSteps() {
+ if (reader[_iteratorFinished]) {
+ return PromiseResolve(createIteratorResult(undefined, true));
+ }
+
+ if (reader[_stream] === undefined) {
+ return PromiseReject(
+ new TypeError(
+ "Cannot get the next iteration result once the reader has been released.",
+ ),
+ );
+ }
+
+ /** @type {Deferred<IteratorResult<any>>} */
+ const promise = new Deferred();
+ /** @type {ReadRequest} */
+ const readRequest = {
+ chunkSteps(chunk) {
+ promise.resolve(createIteratorResult(chunk, false));
+ },
+ closeSteps() {
+ readableStreamDefaultReaderRelease(reader);
+ promise.resolve(createIteratorResult(undefined, true));
+ },
+ errorSteps(e) {
+ readableStreamDefaultReaderRelease(reader);
+ promise.reject(e);
+ },
+ };
+
+ readableStreamDefaultReaderRead(reader, readRequest);
+ return PromisePrototypeThen(promise.promise, (result) => {
+ reader[_iteratorNext] = null;
+ if (result.done === true) {
+ reader[_iteratorFinished] = true;
+ return createIteratorResult(undefined, true);
+ }
+ return result;
+ }, (reason) => {
+ reader[_iteratorNext] = null;
+ reader[_iteratorFinished] = true;
+ throw reason;
+ });
}
- /** @type {Deferred<IteratorResult<any>>} */
- const promise = new Deferred();
- /** @type {ReadRequest} */
- const readRequest = {
- chunkSteps(chunk) {
- promise.resolve(createIteratorResult(chunk, false));
- },
- closeSteps() {
- readableStreamDefaultReaderRelease(reader);
- promise.resolve(createIteratorResult(undefined, true));
- },
- errorSteps(e) {
- readableStreamDefaultReaderRelease(reader);
- promise.reject(e);
- },
- };
- readableStreamDefaultReaderRead(reader, readRequest);
- return promise.promise;
+
+ reader[_iteratorNext] = reader[_iteratorNext]
+ ? PromisePrototypeThen(reader[_iteratorNext], nextSteps, nextSteps)
+ : nextSteps();
+
+ return reader[_iteratorNext];
},
/**
* @param {unknown} arg
* @returns {Promise<IteratorResult<unknown>>}
*/
- async return(arg) {
+ return(arg) {
/** @type {ReadableStreamDefaultReader} */
const reader = this[_reader];
- if (reader[_stream] === undefined) {
- return createIteratorResult(undefined, true);
- }
- assert(reader[_readRequests].length === 0);
- if (this[_preventCancel] === false) {
- const result = readableStreamReaderGenericCancel(reader, arg);
+ const returnSteps = () => {
+ if (reader[_iteratorFinished]) {
+ return PromiseResolve(createIteratorResult(arg, true));
+ }
+ reader[_iteratorFinished] = true;
+
+ if (reader[_stream] === undefined) {
+ return PromiseResolve(createIteratorResult(undefined, true));
+ }
+ assert(reader[_readRequests].length === 0);
+ if (this[_preventCancel] === false) {
+ const result = readableStreamReaderGenericCancel(reader, arg);
+ readableStreamDefaultReaderRelease(reader);
+ return result;
+ }
readableStreamDefaultReaderRelease(reader);
- await result;
- return createIteratorResult(arg, true);
- }
- readableStreamDefaultReaderRelease(reader);
- return createIteratorResult(undefined, true);
+ return PromiseResolve(createIteratorResult(undefined, true));
+ };
+
+ const returnPromise = reader[_iteratorNext]
+ ? PromisePrototypeThen(reader[_iteratorNext], returnSteps, returnSteps)
+ : returnSteps();
+ return PromisePrototypeThen(
+ returnPromise,
+ () => createIteratorResult(arg, true),
+ );
},
}, asyncIteratorPrototype);