diff --git a/CHANGELOG.md b/CHANGELOG.md index e4f0e45..4de048c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ ## Unreleased +* 👓 Align with [spec version `ae5e0cb`](https://github.com/whatwg/streams/tree/ae5e0cb41e9f72cdd97f3a6d47bc674c1f4049d1/) ([#33](https://github.com/MattiasBuelens/web-streams-polyfill/pull/33)) + ## v2.0.4 (2019-08-01) * 🐛 Fix pipe not aborting when both `preventAbort` and `preventCancel` are set ([#31](https://github.com/MattiasBuelens/web-streams-polyfill/pull/31)) diff --git a/README.md b/README.md index 54038c5..a66460e 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ The `polyfill/es2018` and `ponyfill/es2018` variants work in any ES2018-compatib ### Compliance -The polyfill implements [version `e4d3b1a` (29 Jul 2019)][spec-snapshot] of the streams specification. +The polyfill implements [version `ae5e0cb` (23 Aug 2019)][spec-snapshot] of the streams specification. The polyfill is tested against the same [web platform tests][wpt] that are used by browsers to test their native implementations. The polyfill aims to pass all tests, although it allows some exceptions for practical reasons: @@ -99,12 +99,12 @@ Thanks to these people for their work on [the original polyfill][creatorrr-polyf [promise-support]: https://kangax.github.io/compat-table/es6/#test-Promise [promise-polyfill]: https://www.npmjs.com/package/promise-polyfill [rs-asynciterator]: https://streams.spec.whatwg.org/#rs-asynciterator -[spec-snapshot]: https://streams.spec.whatwg.org/commit-snapshots/e4d3b1a826e34d27a7cb5485a1cc4b078608c9ec/ -[wpt]: https://github.com/web-platform-tests/wpt/tree/0da3476dcd5fd3148041d090d2330cf8d412d7f9/streams -[wpt-detached-buffer]: https://github.com/web-platform-tests/wpt/blob/0da3476dcd5fd3148041d090d2330cf8d412d7f9/streams/readable-byte-streams/detached-buffers.any.js +[spec-snapshot]: https://streams.spec.whatwg.org/commit-snapshots/ae5e0cb41e9f72cdd97f3a6d47bc674c1f4049d1/ +[wpt]: https://github.com/web-platform-tests/wpt/tree/7046bf42a72ef21e5e39267d89dc3e30be6d72e3/streams +[wpt-detached-buffer]: https://github.com/web-platform-tests/wpt/blob/7046bf42a72ef21e5e39267d89dc3e30be6d72e3/streams/readable-byte-streams/detached-buffers.any.js [proposal-arraybuffer-transfer]: https://github.com/domenic/proposal-arraybuffer-transfer -[ref-impl-transferarraybuffer]: https://github.com/whatwg/streams/blob/e4d3b1a826e34d27a7cb5485a1cc4b078608c9ec/reference-implementation/lib/helpers.js#L119 +[ref-impl-transferarraybuffer]: https://github.com/whatwg/streams/blob/ae5e0cb41e9f72cdd97f3a6d47bc674c1f4049d1/reference-implementation/lib/helpers.js#L120 [issue-3]: https://github.com/MattiasBuelens/web-streams-polyfill/issues/3 -[wpt-async-iterator-prototype]: https://github.com/web-platform-tests/wpt/blob/0da3476dcd5fd3148041d090d2330cf8d412d7f9/streams/readable-streams/async-iterator.any.js#L17 +[wpt-async-iterator-prototype]: https://github.com/web-platform-tests/wpt/blob/7046bf42a72ef21e5e39267d89dc3e30be6d72e3/streams/readable-streams/async-iterator.any.js#L17 [stub-async-iterator-prototype]: https://github.com/MattiasBuelens/web-streams-polyfill/blob/v2.0.0/src/target/es5/stub/async-iterator-prototype.ts [creatorrr-polyfill]: https://github.com/creatorrr/web-streams-polyfill diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts index 56bfb3c..91bc506 100644 --- a/src/lib/helpers.ts +++ b/src/lib/helpers.ts @@ -1,5 +1,6 @@ import assert from '../stub/assert'; import NumberIsNaN from '../stub/number-isnan'; +import { rethrowAssertionErrorRejection } from './utils'; import { FunctionPropertyNames, InferFirst, InferFunction, InferRest, Promisify } from '../util/type-utils'; function IsPropertyKey(argument: any): argument is string | symbol { @@ -101,7 +102,7 @@ export function CreateAlgorithmFromUnderlyingMethod(underlyingObject: any, } } } - return () => Promise.resolve(); + return () => promiseResolvedWith(undefined); } export function InvokeOrNoop> = FunctionPropertyNames>>( @@ -127,9 +128,9 @@ export function PromiseCall(F: (this: T, ...args: A) => R assert(V !== undefined); assert(Array.isArray(args)); try { - return Promise.resolve(Call(F, V, args)); + return promiseResolvedWith(Call(F, V, args)); } catch (value) { - return Promise.reject(value); + return promiseRejectedWith(value); } } @@ -161,3 +162,62 @@ export function MakeSizeAlgorithmFromSizeFunction(size?: (chunk: T) => number } return chunk => size(chunk); } + +const originalPromise = Promise; +const originalPromiseThen = Promise.prototype.then; +const originalPromiseResolve = Promise.resolve.bind(originalPromise); +const originalPromiseReject = Promise.reject.bind(originalPromise); + +export function newPromise(executor: ( + resolve: (value?: T | PromiseLike) => void, + reject: (reason?: any) => void +) => void): Promise { + return new originalPromise(executor); +} + +export function promiseResolvedWith(value: T | PromiseLike): Promise { + return originalPromiseResolve(value); +} + +export function promiseRejectedWith(reason: any): Promise { + return originalPromiseReject(reason); +} + +export function PerformPromiseThen( + promise: Promise, + onFulfilled?: (value: T) => TResult1 | PromiseLike, + onRejected?: (reason: any) => TResult2 | PromiseLike): Promise { + // There doesn't appear to be any way to correctly emulate the behaviour from JavaScript, so this is just an + // approximation. + return originalPromiseThen.call(promise, onFulfilled, onRejected) as Promise; +} + +export function uponPromise( + promise: Promise, + onFulfilled?: (value: T) => void | PromiseLike, + onRejected?: (reason: any) => void | PromiseLike): void { + PerformPromiseThen( + PerformPromiseThen(promise, onFulfilled, onRejected), + undefined, + rethrowAssertionErrorRejection + ); +} + +export function uponFulfillment(promise: Promise, onFulfilled: (value: T) => void | PromiseLike): void { + uponPromise(promise, onFulfilled); +} + +export function uponRejection(promise: Promise, onRejected: (reason: any) => void | PromiseLike): void { + uponPromise(promise, undefined, onRejected); +} + +export function transformPromiseWith( + promise: Promise, + fulfillmentHandler?: (value: T) => TResult1 | PromiseLike, + rejectionHandler?: (reason: any) => TResult2 | PromiseLike): Promise { + return PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler); +} + +export function setPromiseIsHandledToTrue(promise: Promise): void { + PerformPromiseThen(promise, undefined, rethrowAssertionErrorRejection); +} diff --git a/src/lib/readable-stream.ts b/src/lib/readable-stream.ts index f1934b5..9db7472 100644 --- a/src/lib/readable-stream.ts +++ b/src/lib/readable-stream.ts @@ -5,6 +5,10 @@ import { createArrayFromList, IsNonNegativeNumber, MakeSizeAlgorithmFromSizeFunction, + promiseRejectedWith, + promiseResolvedWith, + setPromiseIsHandledToTrue, + transformPromiseWith, typeIsObject, ValidateAndNormalizeHighWaterMark } from './helpers'; @@ -27,7 +31,6 @@ import { ReadableStreamTee } from './readable-stream/tee'; import { IsWritableStream, IsWritableStreamLocked, WritableStream } from './writable-stream'; import NumberIsInteger from '../stub/number-isinteger'; import { SimpleQueue } from './simple-queue'; -import { noop } from '../utils'; import { AcquireReadableStreamBYOBReader, IsReadableStreamBYOBReader, @@ -55,6 +58,7 @@ import { UnderlyingByteSource, UnderlyingSource } from './readable-stream/underlying-source'; +import { noop } from '../utils'; export type ReadableByteStream = ReadableStream; @@ -129,11 +133,11 @@ export class ReadableStream { cancel(reason: any): Promise { if (IsReadableStream(this) === false) { - return Promise.reject(streamBrandCheckException('cancel')); + return promiseRejectedWith(streamBrandCheckException('cancel')); } if (IsReadableStreamLocked(this) === true) { - return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader')); + return promiseRejectedWith(new TypeError('Cannot cancel a stream that already has a reader')); } return ReadableStreamCancel(this, reason); @@ -190,7 +194,7 @@ export class ReadableStream { const promise = ReadableStreamPipeTo(this, writable, preventClose, preventAbort, preventCancel, signal); - promise.catch(noop); + setPromiseIsHandledToTrue(promise); return readable; } @@ -198,10 +202,10 @@ export class ReadableStream { pipeTo(dest: WritableStream, { preventClose, preventAbort, preventCancel, signal }: PipeOptions = {}): Promise { if (IsReadableStream(this) === false) { - return Promise.reject(streamBrandCheckException('pipeTo')); + return promiseRejectedWith(streamBrandCheckException('pipeTo')); } if (IsWritableStream(dest) === false) { - return Promise.reject( + return promiseRejectedWith( new TypeError('ReadableStream.prototype.pipeTo\'s first argument must be a WritableStream')); } @@ -210,14 +214,17 @@ export class ReadableStream { preventCancel = Boolean(preventCancel); if (signal !== undefined && !isAbortSignal(signal)) { - return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\'s signal option must be an AbortSignal')); + return promiseRejectedWith( + new TypeError('ReadableStream.prototype.pipeTo\'s signal option must be an AbortSignal')); } if (IsReadableStreamLocked(this) === true) { - return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream')); + return promiseRejectedWith( + new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream')); } if (IsWritableStreamLocked(dest) === true) { - return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream')); + return promiseRejectedWith( + new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream')); } return ReadableStreamPipeTo(this, dest, preventClose, preventAbort, preventCancel, signal); @@ -348,16 +355,16 @@ export function ReadableStreamCancel(stream: ReadableStream, reason: any): stream._disturbed = true; if (stream._state === 'closed') { - return Promise.resolve(undefined); + return promiseResolvedWith(undefined); } if (stream._state === 'errored') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } ReadableStreamClose(stream); const sourceCancelPromise = stream._readableStreamController[CancelSteps](reason); - return sourceCancelPromise.then(() => undefined); + return transformPromiseWith(sourceCancelPromise, noop); } export function ReadableStreamClose(stream: ReadableStream): void { diff --git a/src/lib/readable-stream/async-iterator.ts b/src/lib/readable-stream/async-iterator.ts index effce1f..ca51a49 100644 --- a/src/lib/readable-stream/async-iterator.ts +++ b/src/lib/readable-stream/async-iterator.ts @@ -13,7 +13,7 @@ import { readerLockException } from './generic-reader'; import assert from '../../stub/assert'; -import { typeIsObject } from '../helpers'; +import { promiseRejectedWith, promiseResolvedWith, transformPromiseWith, typeIsObject } from '../helpers'; import { AsyncIteratorPrototype } from '@@target/stub/async-iterator-prototype'; export interface ReadableStreamAsyncIterator extends AsyncIterator { @@ -36,13 +36,13 @@ declare class ReadableStreamAsyncIteratorImpl implements ReadableStreamAsyncI const ReadableStreamAsyncIteratorPrototype: ReadableStreamAsyncIteratorImpl = { next(): Promise> { if (IsReadableStreamAsyncIterator(this) === false) { - return Promise.reject(streamAsyncIteratorBrandCheckException('next')); + return promiseRejectedWith(streamAsyncIteratorBrandCheckException('next')); } const reader = this._asyncIteratorReader; if (reader._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('iterate')); + return promiseRejectedWith(readerLockException('iterate')); } - return ReadableStreamDefaultReaderRead(reader).then(result => { + return transformPromiseWith(ReadableStreamDefaultReaderRead(reader), result => { assert(typeIsObject(result)); const done = result.done; assert(typeof done === 'boolean'); @@ -56,23 +56,23 @@ const ReadableStreamAsyncIteratorPrototype: ReadableStreamAsyncIteratorImpl return(value: any): Promise> { if (IsReadableStreamAsyncIterator(this) === false) { - return Promise.reject(streamAsyncIteratorBrandCheckException('next')); + return promiseRejectedWith(streamAsyncIteratorBrandCheckException('next')); } const reader = this._asyncIteratorReader; if (reader._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('finish iterating')); + return promiseRejectedWith(readerLockException('finish iterating')); } if (reader._readRequests.length > 0) { - return Promise.reject(new TypeError( + return promiseRejectedWith(new TypeError( 'Tried to release a reader lock when that reader has pending read() calls un-settled')); } if (this._preventCancel === false) { const result = ReadableStreamReaderGenericCancel(reader, value); ReadableStreamReaderGenericRelease(reader); - return result.then(() => ReadableStreamCreateReadResult(value, true, true)); + return transformPromiseWith(result, () => ReadableStreamCreateReadResult(value, true, true)); } ReadableStreamReaderGenericRelease(reader); - return Promise.resolve(ReadableStreamCreateReadResult(value, true, true)); + return promiseResolvedWith(ReadableStreamCreateReadResult(value, true, true)); } } as any; if (AsyncIteratorPrototype !== undefined) { diff --git a/src/lib/readable-stream/byob-reader.ts b/src/lib/readable-stream/byob-reader.ts index 56eec82..6f3dc2c 100644 --- a/src/lib/readable-stream/byob-reader.ts +++ b/src/lib/readable-stream/byob-reader.ts @@ -1,4 +1,4 @@ -import { IsDetachedBuffer, typeIsObject } from '../helpers'; +import { IsDetachedBuffer, newPromise, promiseRejectedWith, typeIsObject } from '../helpers'; import assert from '../../stub/assert'; import { SimpleQueue } from '../simple-queue'; import { @@ -31,7 +31,7 @@ export function ReadableStreamAddReadIntoRequest(stre assert(IsReadableStreamBYOBReader(stream._reader) === true); assert(stream._state === 'readable' || stream._state === 'closed'); - const promise = new Promise>((resolve, reject) => { + const promise = newPromise>((resolve, reject) => { const readIntoRequest: ReadIntoRequest = { _resolve: resolve, _reject: reject @@ -115,7 +115,7 @@ export class ReadableStreamBYOBReader { get closed(): Promise { if (!IsReadableStreamBYOBReader(this)) { - return Promise.reject(byobReaderBrandCheckException('closed')); + return promiseRejectedWith(byobReaderBrandCheckException('closed')); } return this._closedPromise; @@ -123,11 +123,11 @@ export class ReadableStreamBYOBReader { cancel(reason: any): Promise { if (!IsReadableStreamBYOBReader(this)) { - return Promise.reject(byobReaderBrandCheckException('cancel')); + return promiseRejectedWith(byobReaderBrandCheckException('cancel')); } if (this._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('cancel')); + return promiseRejectedWith(readerLockException('cancel')); } return ReadableStreamReaderGenericCancel(this, reason); @@ -135,23 +135,23 @@ export class ReadableStreamBYOBReader { read(view: T): Promise> { if (!IsReadableStreamBYOBReader(this)) { - return Promise.reject(byobReaderBrandCheckException('read')); + return promiseRejectedWith(byobReaderBrandCheckException('read')); } if (this._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('read from')); + return promiseRejectedWith(readerLockException('read from')); } if (!ArrayBuffer.isView(view)) { - return Promise.reject(new TypeError('view must be an array buffer view')); + return promiseRejectedWith(new TypeError('view must be an array buffer view')); } if (IsDetachedBuffer(view.buffer) === true) { - return Promise.reject(new TypeError('Cannot read into a view onto a detached ArrayBuffer')); + return promiseRejectedWith(new TypeError('Cannot read into a view onto a detached ArrayBuffer')); } if (view.byteLength === 0) { - return Promise.reject(new TypeError('view must have non-zero byteLength')); + return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); } return ReadableStreamBYOBReaderRead(this, view); @@ -197,7 +197,7 @@ function ReadableStreamBYOBReaderRead(reader: Readabl stream._disturbed = true; if (stream._state === 'errored') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } // Controllers must implement this. diff --git a/src/lib/readable-stream/byte-stream-controller.ts b/src/lib/readable-stream/byte-stream-controller.ts index 969ed61..ca3e7e0 100644 --- a/src/lib/readable-stream/byte-stream-controller.ts +++ b/src/lib/readable-stream/byte-stream-controller.ts @@ -1,5 +1,4 @@ import assert from '../../stub/assert'; -import { rethrowAssertionErrorRejection } from '../utils'; import { SimpleQueue } from '../simple-queue'; import { ArrayBufferCopy, @@ -7,8 +6,11 @@ import { InvokeOrNoop, IsDetachedBuffer, IsFiniteNonNegativeNumber, + promiseRejectedWith, + promiseResolvedWith, TransferArrayBuffer, typeIsObject, + uponPromise, ValidateAndNormalizeHighWaterMark } from '../helpers'; import { ResetQueue } from '../queue-with-sizes'; @@ -273,10 +275,10 @@ export class ReadableByteStreamController { try { view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); } catch (viewE) { - return Promise.reject(viewE); + return promiseRejectedWith(viewE); } - return Promise.resolve(ReadableStreamCreateReadResult(view, false, stream._reader!._forAuthorCode)); + return promiseResolvedWith(ReadableStreamCreateReadResult(view, false, stream._reader!._forAuthorCode)); } const autoAllocateChunkSize = this._autoAllocateChunkSize; @@ -285,7 +287,7 @@ export class ReadableByteStreamController { try { buffer = new ArrayBuffer(autoAllocateChunkSize); } catch (bufferE) { - return Promise.reject(bufferE); + return promiseRejectedWith(bufferE); } const pullIntoDescriptor: DefaultPullIntoDescriptor = { @@ -352,7 +354,8 @@ function ReadableByteStreamControllerCallPullIfNeeded(controller: ReadableByteSt // TODO: Test controller argument const pullPromise = controller._pullAlgorithm(); - pullPromise.then( + uponPromise( + pullPromise, () => { controller._pulling = false; @@ -364,7 +367,7 @@ function ReadableByteStreamControllerCallPullIfNeeded(controller: ReadableByteSt e => { ReadableByteStreamControllerError(controller, e); } - ).catch(rethrowAssertionErrorRejection); + ); } function ReadableByteStreamControllerClearPendingPullIntos(controller: ReadableByteStreamController) { @@ -545,7 +548,7 @@ export function ReadableByteStreamControllerPullInto( if (stream._state === 'closed') { const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); - return Promise.resolve(ReadableStreamCreateReadResult(emptyView, true, stream._reader!._forAuthorCode)); + return promiseResolvedWith(ReadableStreamCreateReadResult(emptyView, true, stream._reader!._forAuthorCode)); } if (controller._queueTotalSize > 0) { @@ -554,14 +557,14 @@ export function ReadableByteStreamControllerPullInto( ReadableByteStreamControllerHandleQueueDrain(controller); - return Promise.resolve(ReadableStreamCreateReadResult(filledView, false, stream._reader!._forAuthorCode)); + return promiseResolvedWith(ReadableStreamCreateReadResult(filledView, false, stream._reader!._forAuthorCode)); } if (controller._closeRequested === true) { const e = new TypeError('Insufficient bytes to fill elements in the given buffer'); ReadableByteStreamControllerError(controller, e); - return Promise.reject(e); + return promiseRejectedWith(e); } } @@ -838,7 +841,8 @@ export function SetUpReadableByteStreamController(stream: ReadableByteStream, stream._readableStreamController = controller; const startResult = startAlgorithm(); - Promise.resolve(startResult).then( + uponPromise( + promiseResolvedWith(startResult), () => { controller._started = true; @@ -850,7 +854,7 @@ export function SetUpReadableByteStreamController(stream: ReadableByteStream, r => { ReadableByteStreamControllerError(controller, r); } - ).catch(rethrowAssertionErrorRejection); + ); } export function SetUpReadableByteStreamControllerFromUnderlyingSource(stream: ReadableByteStream, diff --git a/src/lib/readable-stream/default-controller.ts b/src/lib/readable-stream/default-controller.ts index 3322a2b..5bbb097 100644 --- a/src/lib/readable-stream/default-controller.ts +++ b/src/lib/readable-stream/default-controller.ts @@ -1,7 +1,6 @@ import { QueuingStrategySizeCallback } from '../queuing-strategy'; import assert from '../../stub/assert'; import { DequeueValue, EnqueueValueWithSize, QueuePair, ResetQueue } from '../queue-with-sizes'; -import { rethrowAssertionErrorRejection } from '../utils'; import { ReadableStreamAddReadRequest, ReadableStreamFulfillReadRequest, @@ -10,7 +9,13 @@ import { import { SimpleQueue } from '../simple-queue'; import { CancelSteps, PullSteps } from './symbols'; import { ReadableStreamCreateReadResult, ReadResult } from './generic-reader'; -import { CreateAlgorithmFromUnderlyingMethod, InvokeOrNoop, typeIsObject } from '../helpers'; +import { + CreateAlgorithmFromUnderlyingMethod, + InvokeOrNoop, + promiseResolvedWith, + typeIsObject, + uponPromise +} from '../helpers'; import { IsReadableStreamLocked, ReadableStream, ReadableStreamClose, ReadableStreamError } from '../readable-stream'; import { UnderlyingSource } from './underlying-source'; @@ -107,7 +112,7 @@ export class ReadableStreamDefaultController { ReadableStreamDefaultControllerCallPullIfNeeded(this); } - return Promise.resolve(ReadableStreamCreateReadResult(chunk, false, stream._reader!._forAuthorCode)); + return promiseResolvedWith(ReadableStreamCreateReadResult(chunk, false, stream._reader!._forAuthorCode)); } const pendingPromise = ReadableStreamAddReadRequest(stream); @@ -146,7 +151,8 @@ function ReadableStreamDefaultControllerCallPullIfNeeded(controller: ReadableStr controller._pulling = true; const pullPromise = controller._pullAlgorithm(); - pullPromise.then( + uponPromise( + pullPromise, () => { controller._pulling = false; @@ -158,7 +164,7 @@ function ReadableStreamDefaultControllerCallPullIfNeeded(controller: ReadableStr e => { ReadableStreamDefaultControllerError(controller, e); } - ).catch(rethrowAssertionErrorRejection); + ); } function ReadableStreamDefaultControllerShouldCallPull(controller: ReadableStreamDefaultController): boolean { @@ -308,7 +314,8 @@ export function SetUpReadableStreamDefaultController(stream: ReadableStream { controller._started = true; @@ -320,7 +327,7 @@ export function SetUpReadableStreamDefaultController(stream: ReadableStream { ReadableStreamDefaultControllerError(controller, r); } - ).catch(rethrowAssertionErrorRejection); + ); } export function SetUpReadableStreamDefaultControllerFromUnderlyingSource(stream: ReadableStream, diff --git a/src/lib/readable-stream/default-reader.ts b/src/lib/readable-stream/default-reader.ts index 085b7a5..fefdbc6 100644 --- a/src/lib/readable-stream/default-reader.ts +++ b/src/lib/readable-stream/default-reader.ts @@ -1,4 +1,4 @@ -import { typeIsObject } from '../helpers'; +import { newPromise, promiseRejectedWith, promiseResolvedWith, typeIsObject } from '../helpers'; import assert from '../../stub/assert'; import { SimpleQueue } from '../simple-queue'; import { @@ -27,7 +27,7 @@ export function ReadableStreamAddReadRequest(stream: ReadableStream): Prom assert(IsReadableStreamDefaultReader(stream._reader) === true); assert(stream._state === 'readable'); - const promise = new Promise>((resolve, reject) => { + const promise = newPromise>((resolve, reject) => { const readRequest: ReadRequest = { _resolve: resolve, _reject: reject @@ -104,7 +104,7 @@ export class ReadableStreamDefaultReader { get closed(): Promise { if (!IsReadableStreamDefaultReader(this)) { - return Promise.reject(defaultReaderBrandCheckException('closed')); + return promiseRejectedWith(defaultReaderBrandCheckException('closed')); } return this._closedPromise; @@ -112,11 +112,11 @@ export class ReadableStreamDefaultReader { cancel(reason: any): Promise { if (!IsReadableStreamDefaultReader(this)) { - return Promise.reject(defaultReaderBrandCheckException('cancel')); + return promiseRejectedWith(defaultReaderBrandCheckException('cancel')); } if (this._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('cancel')); + return promiseRejectedWith(readerLockException('cancel')); } return ReadableStreamReaderGenericCancel(this, reason); @@ -124,11 +124,11 @@ export class ReadableStreamDefaultReader { read(): Promise> { if (!IsReadableStreamDefaultReader(this)) { - return Promise.reject(defaultReaderBrandCheckException('read')); + return promiseRejectedWith(defaultReaderBrandCheckException('read')); } if (this._ownerReadableStream === undefined) { - return Promise.reject(readerLockException('read from')); + return promiseRejectedWith(readerLockException('read from')); } return ReadableStreamDefaultReaderRead(this); @@ -173,11 +173,11 @@ export function ReadableStreamDefaultReaderRead(reader: ReadableStreamDefault stream._disturbed = true; if (stream._state === 'closed') { - return Promise.resolve(ReadableStreamCreateReadResult(undefined, true, reader._forAuthorCode)); + return promiseResolvedWith(ReadableStreamCreateReadResult(undefined, true, reader._forAuthorCode)); } if (stream._state === 'errored') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } assert(stream._state === 'readable'); diff --git a/src/lib/readable-stream/generic-reader.ts b/src/lib/readable-stream/generic-reader.ts index bf19212..34c4b7c 100644 --- a/src/lib/readable-stream/generic-reader.ts +++ b/src/lib/readable-stream/generic-reader.ts @@ -1,6 +1,6 @@ import assert from '../../stub/assert'; -import { noop } from '../../utils'; import { ReadableStream, ReadableStreamCancel, ReadableStreamReader } from '../readable-stream'; +import { newPromise, setPromiseIsHandledToTrue } from '../helpers'; // TODO Fix ReadableStreamReadResult in TypeScript DOM types export interface ReadResult { @@ -74,7 +74,7 @@ export function readerLockException(name: string): TypeError { // Helper functions for the ReadableStreamDefaultReader. export function defaultReaderClosedPromiseInitialize(reader: ReadableStreamReader) { - reader._closedPromise = new Promise((resolve, reject) => { + reader._closedPromise = newPromise((resolve, reject) => { reader._closedPromise_resolve = resolve; reader._closedPromise_reject = reject; }); @@ -94,7 +94,7 @@ export function defaultReaderClosedPromiseReject(reader: ReadableStreamReader(source: ReadableStream, @@ -43,9 +51,9 @@ export function ReadableStreamPipeTo(source: ReadableStream, let shuttingDown = false; // This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown. - let currentWrite = Promise.resolve(); + let currentWrite = promiseResolvedWith(undefined); - return new Promise((resolve, reject) => { + return newPromise((resolve, reject) => { let abortAlgorithm: () => void; if (signal !== undefined) { abortAlgorithm = () => { @@ -56,7 +64,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, if (dest._state === 'writable') { return WritableStreamAbort(dest, error); } - return Promise.resolve(); + return promiseResolvedWith(undefined); }); } if (preventCancel === false) { @@ -64,7 +72,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, if (source._state === 'readable') { return ReadableStreamCancel(source, error); } - return Promise.resolve(); + return promiseResolvedWith(undefined); }); } shutdownWithAction(() => Promise.all(actions.map(action => action())), true, error); @@ -82,12 +90,14 @@ export function ReadableStreamPipeTo(source: ReadableStream, // - Backpressure must be enforced // - Shutdown must stop all activity function pipeLoop() { - return new Promise((resolveLoop, rejectLoop) => { + return newPromise((resolveLoop, rejectLoop) => { function next(done: boolean) { if (done) { resolveLoop(); } else { - pipeStep().then(next, rejectLoop); + // Use `PerformPromiseThen` instead of `uponPromise` to avoid + // adding unnecessary `.catch(rethrowAssertionErrorRejection)` handlers + PerformPromiseThen(pipeStep(), next, rejectLoop); } } @@ -97,16 +107,16 @@ export function ReadableStreamPipeTo(source: ReadableStream, function pipeStep(): Promise { if (shuttingDown === true) { - return Promise.resolve(true); + return promiseResolvedWith(true); } - return writer._readyPromise.then(() => { - return ReadableStreamDefaultReaderRead(reader).then(({ value, done }) => { + return PerformPromiseThen(writer._readyPromise, () => { + return PerformPromiseThen(ReadableStreamDefaultReaderRead(reader), ({ value, done }) => { if (done === true) { return true; } - currentWrite = WritableStreamDefaultWriterWrite(writer, value!).catch(noop); + currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, value), undefined, noop); return false; }); }); @@ -150,13 +160,16 @@ export function ReadableStreamPipeTo(source: ReadableStream, } } - pipeLoop().catch(rethrowAssertionErrorRejection); + setPromiseIsHandledToTrue(pipeLoop()); function waitForWritesToFinish(): Promise { // Another write may have started while we were waiting on this currentWrite, so we have to be sure to wait // for that too. const oldCurrentWrite = currentWrite; - return currentWrite.then(() => oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined); + return PerformPromiseThen( + currentWrite, + () => oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined + ); } function isOrBecomesErrored(stream: ReadableStream | WritableStream, @@ -165,7 +178,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, if (stream._state === 'errored') { action(stream._storedError); } else { - promise.catch(action).catch(rethrowAssertionErrorRejection); + uponRejection(promise, action); } } @@ -173,7 +186,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, if (stream._state === 'closed') { action(); } else { - promise.then(action).catch(rethrowAssertionErrorRejection); + uponFulfillment(promise, action); } } @@ -184,16 +197,17 @@ export function ReadableStreamPipeTo(source: ReadableStream, shuttingDown = true; if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { - waitForWritesToFinish().then(doTheRest); + uponFulfillment(waitForWritesToFinish(), doTheRest); } else { doTheRest(); } function doTheRest() { - action().then( + uponPromise( + action(), () => finalize(originalIsError, originalError), newError => finalize(true, newError) - ).catch(rethrowAssertionErrorRejection); + ); } } @@ -204,7 +218,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, shuttingDown = true; if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { - waitForWritesToFinish().then(() => finalize(isError, error)).catch(rethrowAssertionErrorRejection); + uponFulfillment(waitForWritesToFinish(), () => finalize(isError, error)); } else { finalize(isError, error); } diff --git a/src/lib/readable-stream/tee.ts b/src/lib/readable-stream/tee.ts index 0433422..51b45d8 100644 --- a/src/lib/readable-stream/tee.ts +++ b/src/lib/readable-stream/tee.ts @@ -1,8 +1,15 @@ import { CreateReadableStream, IsReadableStream, ReadableStream, ReadableStreamCancel } from '../readable-stream'; import { AcquireReadableStreamDefaultReader, ReadableStreamDefaultReaderRead } from './default-reader'; import assert from '../../stub/assert'; -import { createArrayFromList, typeIsObject } from '../helpers'; -import { rethrowAssertionErrorRejection } from '../utils'; +import { + createArrayFromList, + newPromise, + promiseResolvedWith, + setPromiseIsHandledToTrue, + transformPromiseWith, + typeIsObject, + uponRejection +} from '../helpers'; import { ReadableStreamDefaultController, ReadableStreamDefaultControllerClose, @@ -26,18 +33,18 @@ export function ReadableStreamTee(stream: ReadableStream, let branch2: ReadableStream; let resolveCancelPromise: (reason: any) => void; - const cancelPromise = new Promise(resolve => { + const cancelPromise = newPromise(resolve => { resolveCancelPromise = resolve; }); function pullAlgorithm(): Promise { if (reading === true) { - return Promise.resolve(); + return promiseResolvedWith(undefined); } reading = true; - const readPromise = ReadableStreamDefaultReaderRead(reader).then(result => { + const readPromise = transformPromiseWith(ReadableStreamDefaultReaderRead(reader), result => { reading = false; assert(typeIsObject(result)); @@ -79,9 +86,9 @@ export function ReadableStreamTee(stream: ReadableStream, } }); - readPromise.catch(rethrowAssertionErrorRejection); + setPromiseIsHandledToTrue(readPromise); - return Promise.resolve(); + return promiseResolvedWith(undefined); } function cancel1Algorithm(reason: any): Promise { @@ -111,7 +118,7 @@ export function ReadableStreamTee(stream: ReadableStream, branch1 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm); branch2 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm); - reader._closedPromise.catch((r: any) => { + uponRejection(reader._closedPromise, (r: any) => { ReadableStreamDefaultControllerError(branch1._readableStreamController as ReadableStreamDefaultController, r); ReadableStreamDefaultControllerError(branch2._readableStreamController as ReadableStreamDefaultController, r); }); diff --git a/src/lib/transform-stream.ts b/src/lib/transform-stream.ts index 805eb24..56678af 100644 --- a/src/lib/transform-stream.ts +++ b/src/lib/transform-stream.ts @@ -4,7 +4,11 @@ import { InvokeOrNoop, IsNonNegativeNumber, MakeSizeAlgorithmFromSizeFunction, + newPromise, PromiseCall, + promiseRejectedWith, + promiseResolvedWith, + transformPromiseWith, typeIsObject, ValidateAndNormalizeHighWaterMark } from './helpers'; @@ -86,7 +90,7 @@ export class TransformStream { readableHighWaterMark = ValidateAndNormalizeHighWaterMark(readableHighWaterMark); let startPromise_resolve!: (value: void | PromiseLike) => void; - const startPromise = new Promise(resolve => { + const startPromise = newPromise(resolve => { startPromise_resolve = resolve; }); @@ -132,7 +136,7 @@ export function CreateTransformStream(startAlgorithm: () => void | Promise const stream: TransformStream = Object.create(TransformStream.prototype); let startPromise_resolve!: (value: void | PromiseLike) => void; - const startPromise = new Promise(resolve => { + const startPromise = newPromise(resolve => { startPromise_resolve = resolve; }); @@ -179,7 +183,7 @@ function InitializeTransformStream(stream: TransformStream, function cancelAlgorithm(reason: any): Promise { TransformStreamErrorWritableAndUnblockWrite(stream, reason); - return Promise.resolve(); + return promiseResolvedWith(undefined); } stream._readable = CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark, @@ -233,7 +237,7 @@ function TransformStreamSetBackpressure(stream: TransformStream, backpressure: b stream._backpressureChangePromise_resolve(); } - stream._backpressureChangePromise = new Promise(resolve => { + stream._backpressureChangePromise = newPromise(resolve => { stream._backpressureChangePromise_resolve = resolve; }); @@ -328,9 +332,9 @@ function SetUpTransformStreamDefaultControllerFromTransformer(stream: Tran let transformAlgorithm = (chunk: I) => { try { TransformStreamDefaultControllerEnqueue(controller, chunk as unknown as O); - return Promise.resolve(); + return promiseResolvedWith(undefined); } catch (transformResultE) { - return Promise.reject(transformResultE); + return promiseRejectedWith(transformResultE); } }; const transformMethod = transformer.transform; @@ -386,7 +390,7 @@ function TransformStreamDefaultControllerError(controller: TransformStreamDefaul function TransformStreamDefaultControllerPerformTransform(controller: TransformStreamDefaultController, chunk: I) { const transformPromise = controller._transformAlgorithm(chunk); - return transformPromise.catch(r => { + return transformPromiseWith(transformPromise, undefined, r => { TransformStreamError(controller._controlledTransformStream, r); throw r; }); @@ -414,7 +418,7 @@ function TransformStreamDefaultSinkWriteAlgorithm(stream: TransformStream< if (stream._backpressure === true) { const backpressureChangePromise = stream._backpressureChangePromise; assert(backpressureChangePromise !== undefined); - return backpressureChangePromise.then(() => { + return transformPromiseWith(backpressureChangePromise, () => { const writable = stream._writable; const state = writable._state; if (state === 'erroring') { @@ -432,7 +436,7 @@ function TransformStreamDefaultSinkAbortAlgorithm(stream: TransformStream, reaso // abort() is not called synchronously, so it is possible for abort() to be called when the stream is already // errored. TransformStreamError(stream, reason); - return Promise.resolve(); + return promiseResolvedWith(undefined); } function TransformStreamDefaultSinkCloseAlgorithm(stream: TransformStream): Promise { @@ -444,7 +448,7 @@ function TransformStreamDefaultSinkCloseAlgorithm(stream: TransformStream< TransformStreamDefaultControllerClearAlgorithms(controller); // Return a promise that is fulfilled with undefined on success. - return flushPromise.then(() => { + return transformPromiseWith(flushPromise, () => { if (readable._state === 'errored') { throw readable._storedError; } @@ -452,7 +456,7 @@ function TransformStreamDefaultSinkCloseAlgorithm(stream: TransformStream< if (ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) === true) { ReadableStreamDefaultControllerClose(readableController); } - }).catch(r => { + }, r => { TransformStreamError(stream, r); throw readable._storedError; }); diff --git a/src/lib/writable-stream.ts b/src/lib/writable-stream.ts index 6cd05cb..39b6626 100644 --- a/src/lib/writable-stream.ts +++ b/src/lib/writable-stream.ts @@ -4,14 +4,17 @@ import { InvokeOrNoop, IsNonNegativeNumber, MakeSizeAlgorithmFromSizeFunction, + newPromise, + promiseRejectedWith, + promiseResolvedWith, + setPromiseIsHandledToTrue, typeIsObject, + uponPromise, ValidateAndNormalizeHighWaterMark } from './helpers'; -import { rethrowAssertionErrorRejection } from './utils'; import { DequeueValue, EnqueueValueWithSize, PeekQueueValue, QueuePair, ResetQueue } from './queue-with-sizes'; import { QueuingStrategy, QueuingStrategySizeCallback } from './queuing-strategy'; import { SimpleQueue } from './simple-queue'; -import { noop } from '../utils'; const AbortSteps = Symbol('[[AbortSteps]]'); const ErrorSteps = Symbol('[[ErrorSteps]]'); @@ -102,11 +105,11 @@ class WritableStream { abort(reason: any): Promise { if (IsWritableStream(this) === false) { - return Promise.reject(streamBrandCheckException('abort')); + return promiseRejectedWith(streamBrandCheckException('abort')); } if (IsWritableStreamLocked(this) === true) { - return Promise.reject(new TypeError('Cannot abort a stream that already has a writer')); + return promiseRejectedWith(new TypeError('Cannot abort a stream that already has a writer')); } return WritableStreamAbort(this, reason); @@ -221,7 +224,7 @@ function IsWritableStreamLocked(stream: WritableStream): boolean { function WritableStreamAbort(stream: WritableStream, reason: any): Promise { const state = stream._state; if (state === 'closed' || state === 'errored') { - return Promise.resolve(undefined); + return promiseResolvedWith(undefined); } if (stream._pendingAbortRequest !== undefined) { return stream._pendingAbortRequest._promise; @@ -236,7 +239,7 @@ function WritableStreamAbort(stream: WritableStream, reason: any): Promise reason = undefined; } - const promise = new Promise((resolve, reject) => { + const promise = newPromise((resolve, reject) => { stream._pendingAbortRequest = { _promise: undefined!, _resolve: resolve, @@ -260,7 +263,7 @@ function WritableStreamAddWriteRequest(stream: WritableStream): Promise { assert(IsWritableStreamLocked(stream) === true); assert(stream._state === 'writable'); - const promise = new Promise((resolve, reject) => { + const promise = newPromise((resolve, reject) => { const writeRequest: WriteRequest = { _resolve: resolve, _reject: reject @@ -330,7 +333,8 @@ function WritableStreamFinishErroring(stream: WritableStream) { } const promise = stream._writableStreamController[AbortSteps](abortRequest._reason); - promise.then( + uponPromise( + promise, () => { abortRequest._resolve(); WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); @@ -523,7 +527,7 @@ class WritableStreamDefaultWriter { get closed(): Promise { if (IsWritableStreamDefaultWriter(this) === false) { - return Promise.reject(defaultWriterBrandCheckException('closed')); + return promiseRejectedWith(defaultWriterBrandCheckException('closed')); } return this._closedPromise; @@ -543,7 +547,7 @@ class WritableStreamDefaultWriter { get ready(): Promise { if (IsWritableStreamDefaultWriter(this) === false) { - return Promise.reject(defaultWriterBrandCheckException('ready')); + return promiseRejectedWith(defaultWriterBrandCheckException('ready')); } return this._readyPromise; @@ -551,11 +555,11 @@ class WritableStreamDefaultWriter { abort(reason: any): Promise { if (IsWritableStreamDefaultWriter(this) === false) { - return Promise.reject(defaultWriterBrandCheckException('abort')); + return promiseRejectedWith(defaultWriterBrandCheckException('abort')); } if (this._ownerWritableStream === undefined) { - return Promise.reject(defaultWriterLockException('abort')); + return promiseRejectedWith(defaultWriterLockException('abort')); } return WritableStreamDefaultWriterAbort(this, reason); @@ -563,17 +567,17 @@ class WritableStreamDefaultWriter { close(): Promise { if (IsWritableStreamDefaultWriter(this) === false) { - return Promise.reject(defaultWriterBrandCheckException('close')); + return promiseRejectedWith(defaultWriterBrandCheckException('close')); } const stream = this._ownerWritableStream; if (stream === undefined) { - return Promise.reject(defaultWriterLockException('close')); + return promiseRejectedWith(defaultWriterLockException('close')); } if (WritableStreamCloseQueuedOrInFlight(stream) === true) { - return Promise.reject(new TypeError('cannot close an already-closing stream')); + return promiseRejectedWith(new TypeError('cannot close an already-closing stream')); } return WritableStreamDefaultWriterClose(this); @@ -597,11 +601,11 @@ class WritableStreamDefaultWriter { write(chunk: W): Promise { if (IsWritableStreamDefaultWriter(this) === false) { - return Promise.reject(defaultWriterBrandCheckException('write')); + return promiseRejectedWith(defaultWriterBrandCheckException('write')); } if (this._ownerWritableStream === undefined) { - return Promise.reject(defaultWriterLockException('write to')); + return promiseRejectedWith(defaultWriterLockException('write to')); } return WritableStreamDefaultWriterWrite(this, chunk); @@ -639,14 +643,14 @@ function WritableStreamDefaultWriterClose(writer: WritableStreamDefaultWriter((resolve, reject) => { + const promise = newPromise((resolve, reject) => { const closeRequest: CloseRequest = { _resolve: resolve, _reject: reject @@ -672,11 +676,11 @@ function WritableStreamDefaultWriterCloseWithErrorPropagation(writer: WritableSt const state = stream._state; if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { - return Promise.resolve(); + return promiseResolvedWith(undefined); } if (state === 'errored') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } assert(state === 'writable' || state === 'erroring'); @@ -743,18 +747,18 @@ function WritableStreamDefaultWriterWrite(writer: WritableStreamDefaultWriter const chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk); if (stream !== writer._ownerWritableStream) { - return Promise.reject(defaultWriterLockException('write to')); + return promiseRejectedWith(defaultWriterLockException('write to')); } const state = stream._state; if (state === 'errored') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { - return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to')); + return promiseRejectedWith(new TypeError('The stream is closing or closed and cannot be written to')); } if (state === 'erroring') { - return Promise.reject(stream._storedError); + return promiseRejectedWith(stream._storedError); } assert(state === 'writable'); @@ -873,8 +877,9 @@ function SetUpWritableStreamDefaultController(stream: WritableStream, WritableStreamUpdateBackpressure(stream, backpressure); const startResult = startAlgorithm(); - const startPromise = Promise.resolve(startResult); - startPromise.then( + const startPromise = promiseResolvedWith(startResult); + uponPromise( + startPromise, () => { assert(stream._state === 'writable' || stream._state === 'erroring'); controller._started = true; @@ -885,7 +890,7 @@ function SetUpWritableStreamDefaultController(stream: WritableStream, controller._started = true; WritableStreamDealWithRejection(stream, r); } - ).catch(rethrowAssertionErrorRejection); + ); } function SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream: WritableStream, @@ -1010,14 +1015,15 @@ function WritableStreamDefaultControllerProcessClose(controller: WritableStreamD const sinkClosePromise = controller._closeAlgorithm(); WritableStreamDefaultControllerClearAlgorithms(controller); - sinkClosePromise.then( + uponPromise( + sinkClosePromise, () => { WritableStreamFinishInFlightClose(stream); }, reason => { WritableStreamFinishInFlightCloseWithError(stream, reason); } - ).catch(rethrowAssertionErrorRejection); + ); } function WritableStreamDefaultControllerProcessWrite(controller: WritableStreamDefaultController, chunk: W) { @@ -1026,7 +1032,8 @@ function WritableStreamDefaultControllerProcessWrite(controller: WritableStre WritableStreamMarkFirstWriteRequestInFlight(stream); const sinkWritePromise = controller._writeAlgorithm(chunk); - sinkWritePromise.then( + uponPromise( + sinkWritePromise, () => { WritableStreamFinishInFlightWrite(stream); @@ -1048,7 +1055,7 @@ function WritableStreamDefaultControllerProcessWrite(controller: WritableStre } WritableStreamFinishInFlightWriteWithError(stream, reason); } - ).catch(rethrowAssertionErrorRejection); + ); } function WritableStreamDefaultControllerGetBackpressure(controller: WritableStreamDefaultController): boolean { @@ -1085,7 +1092,7 @@ function defaultWriterLockException(name: string): TypeError { } function defaultWriterClosedPromiseInitialize(writer: WritableStreamDefaultWriter) { - writer._closedPromise = new Promise((resolve, reject) => { + writer._closedPromise = newPromise((resolve, reject) => { writer._closedPromise_resolve = resolve; writer._closedPromise_reject = reject; writer._closedPromiseState = 'pending'; @@ -1107,7 +1114,7 @@ function defaultWriterClosedPromiseReject(writer: WritableStreamDefaultWriter) { - writer._readyPromise = new Promise((resolve, reject) => { + writer._readyPromise = newPromise((resolve, reject) => { writer._readyPromise_resolve = resolve; writer._readyPromise_reject = reject; }); @@ -1155,7 +1162,7 @@ function defaultWriterReadyPromiseReject(writer: WritableStreamDefaultWriter