Skip to content

Commit

Permalink
Merge pull request #67 from MattiasBuelens/fix-resolve-after-reject
Browse files Browse the repository at this point in the history
Ignore resolving/rejecting promises after a previous resolve/reject
  • Loading branch information
MattiasBuelens authored Nov 12, 2020
2 parents 0e2b4e2 + 094c3df commit 65302aa
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

* 📝 Add documentation to type definitions ([#62](https://github.com/MattiasBuelens/web-streams-polyfill/pull/62))
* 👓 Align with [spec version `6cd5e81`](https://github.com/whatwg/streams/tree/6cd5e81f6191fed9e7d99ee73d4941e3060311ce/) ([#63](https://github.com/MattiasBuelens/web-streams-polyfill/pull/63))
* 🐛 Fix an issue where the polyfill could throw an error when resolving/rejecting `reader.closed` when it was already resolved/rejected ([#66](https://github.com/MattiasBuelens/web-streams-polyfill/issues/66), [#67](https://github.com/MattiasBuelens/web-streams-polyfill/pull/67))

## v3.0.0 (2020-07-20)

Expand Down
14 changes: 8 additions & 6 deletions src/lib/readable-stream/generic-reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ export function defaultReaderClosedPromiseInitializeAsResolved(reader: ReadableS
}

export function defaultReaderClosedPromiseReject(reader: ReadableStreamReader<any>, reason: any) {
assert(reader._closedPromise_resolve !== undefined);
assert(reader._closedPromise_reject !== undefined);
if (reader._closedPromise_reject === undefined) {
return;
}

setPromiseIsHandledToTrue(reader._closedPromise);
reader._closedPromise_reject!(reason);
reader._closedPromise_reject(reason);
reader._closedPromise_resolve = undefined;
reader._closedPromise_reject = undefined;
}
Expand All @@ -87,10 +88,11 @@ export function defaultReaderClosedPromiseResetToRejected(reader: ReadableStream
}

export function defaultReaderClosedPromiseResolve(reader: ReadableStreamReader<any>) {
assert(reader._closedPromise_resolve !== undefined);
assert(reader._closedPromise_reject !== undefined);
if (reader._closedPromise_resolve === undefined) {
return;
}

reader._closedPromise_resolve!(undefined);
reader._closedPromise_resolve(undefined);
reader._closedPromise_resolve = undefined;
reader._closedPromise_reject = undefined;
}
28 changes: 16 additions & 12 deletions src/lib/writable-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1266,12 +1266,13 @@ function defaultWriterClosedPromiseInitializeAsResolved(writer: WritableStreamDe
}

function defaultWriterClosedPromiseReject(writer: WritableStreamDefaultWriter, reason: any) {
assert(writer._closedPromise_resolve !== undefined);
assert(writer._closedPromise_reject !== undefined);
if (writer._closedPromise_reject === undefined) {
return;
}
assert(writer._closedPromiseState === 'pending');

setPromiseIsHandledToTrue(writer._closedPromise);
writer._closedPromise_reject!(reason);
writer._closedPromise_reject(reason);
writer._closedPromise_resolve = undefined;
writer._closedPromise_reject = undefined;
writer._closedPromiseState = 'rejected';
Expand All @@ -1286,11 +1287,12 @@ function defaultWriterClosedPromiseResetToRejected(writer: WritableStreamDefault
}

function defaultWriterClosedPromiseResolve(writer: WritableStreamDefaultWriter) {
assert(writer._closedPromise_resolve !== undefined);
assert(writer._closedPromise_reject !== undefined);
if (writer._closedPromise_resolve === undefined) {
return;
}
assert(writer._closedPromiseState === 'pending');

writer._closedPromise_resolve!(undefined);
writer._closedPromise_resolve(undefined);
writer._closedPromise_resolve = undefined;
writer._closedPromise_reject = undefined;
writer._closedPromiseState = 'resolved';
Expand All @@ -1315,11 +1317,12 @@ function defaultWriterReadyPromiseInitializeAsResolved(writer: WritableStreamDef
}

function defaultWriterReadyPromiseReject(writer: WritableStreamDefaultWriter, reason: any) {
assert(writer._readyPromise_resolve !== undefined);
assert(writer._readyPromise_reject !== undefined);
if (writer._readyPromise_reject === undefined) {
return;
}

setPromiseIsHandledToTrue(writer._readyPromise);
writer._readyPromise_reject!(reason);
writer._readyPromise_reject(reason);
writer._readyPromise_resolve = undefined;
writer._readyPromise_reject = undefined;
writer._readyPromiseState = 'rejected';
Expand All @@ -1340,10 +1343,11 @@ function defaultWriterReadyPromiseResetToRejected(writer: WritableStreamDefaultW
}

function defaultWriterReadyPromiseResolve(writer: WritableStreamDefaultWriter) {
assert(writer._readyPromise_resolve !== undefined);
assert(writer._readyPromise_reject !== undefined);
if (writer._readyPromise_resolve === undefined) {
return;
}

writer._readyPromise_resolve!(undefined);
writer._readyPromise_resolve(undefined);
writer._readyPromise_resolve = undefined;
writer._readyPromise_reject = undefined;
writer._readyPromiseState = 'fulfilled';
Expand Down
27 changes: 27 additions & 0 deletions test/unit/readable-stream/regression.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { TransformStream } = require('../../../');

describe('ReadableStream regressions', () => {
// https://github.com/MattiasBuelens/web-streams-polyfill/issues/66
it('#66', async () => {
const { readable, writable } = new TransformStream();

const producer = (async () => {
const writer = writable.getWriter();
await writer.write('hello');
// The async iterator releases its reader lock in the "close steps" of its pending read, which rejects the
// reader's closed promise. However, ReadableStreamClose then tries to resolve that same closed promise.
// This *should* be ignored (since the promise is already rejected), but instead would cause a TypeError.
await writer.close();
})();

const consumer = (async () => {
const results = [];
for await (const chunk of readable) {
results.push(chunk);
}
expect(results).toEqual(['hello']);
})();

await Promise.all([producer, consumer]);
});
});

0 comments on commit 65302aa

Please sign in to comment.