diff --git a/CHANGELOG.md b/CHANGELOG.md index c44e434..80d9f99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ > - 🏠 Internal > - 💅 Polish +## Unreleased + +* 🐛 Prevent [warnings from Bluebird](http://bluebirdjs.com/docs/warning-explanations.html#warning-a-promise-was-created-in-a-handler-but-was-not-returned-from-it) about a promise being created within a handler but not being returned from a handler. ([#91](https://github.com/MattiasBuelens/web-streams-polyfill/pull/91)) + ## v4.0.0-beta.1 (2021-09-06) * 💥 Rework the list of variants to have more modern defaults. diff --git a/src/lib/helpers/webidl.ts b/src/lib/helpers/webidl.ts index 97b5f0c..63ab7af 100644 --- a/src/lib/helpers/webidl.ts +++ b/src/lib/helpers/webidl.ts @@ -30,10 +30,13 @@ export function PerformPromiseThen( return originalPromiseThen.call(promise, onFulfilled, onRejected) as Promise; } +// Bluebird logs a warning when a promise is created within a fulfillment handler, but then isn't returned +// from that handler. To prevent this, return null instead of void from all handlers. +// http://bluebirdjs.com/docs/warning-explanations.html#warning-a-promise-was-created-in-a-handler-but-was-not-returned-from-it export function uponPromise( promise: Promise, - onFulfilled?: (value: T) => void | PromiseLike, - onRejected?: (reason: any) => void | PromiseLike): void { + onFulfilled?: (value: T) => null | PromiseLike, + onRejected?: (reason: any) => null | PromiseLike): void { PerformPromiseThen( PerformPromiseThen(promise, onFulfilled, onRejected), undefined, @@ -41,11 +44,11 @@ export function uponPromise( ); } -export function uponFulfillment(promise: Promise, onFulfilled: (value: T) => void | PromiseLike): void { +export function uponFulfillment(promise: Promise, onFulfilled: (value: T) => null | PromiseLike): void { uponPromise(promise, onFulfilled); } -export function uponRejection(promise: Promise, onRejected: (reason: any) => void | PromiseLike): void { +export function uponRejection(promise: Promise, onRejected: (reason: any) => null | PromiseLike): void { uponPromise(promise, undefined, onRejected); } diff --git a/src/lib/readable-stream/byte-stream-controller.ts b/src/lib/readable-stream/byte-stream-controller.ts index 3d11bbb..77aa091 100644 --- a/src/lib/readable-stream/byte-stream-controller.ts +++ b/src/lib/readable-stream/byte-stream-controller.ts @@ -421,9 +421,12 @@ function ReadableByteStreamControllerCallPullIfNeeded(controller: ReadableByteSt controller._pullAgain = false; ReadableByteStreamControllerCallPullIfNeeded(controller); } + + return null; }, e => { ReadableByteStreamControllerError(controller, e); + return null; } ); } @@ -981,9 +984,11 @@ export function SetUpReadableByteStreamController(stream: ReadableByteStream, assert(!controller._pullAgain); ReadableByteStreamControllerCallPullIfNeeded(controller); + return null; }, r => { ReadableByteStreamControllerError(controller, r); + return null; } ); } @@ -995,18 +1000,24 @@ export function SetUpReadableByteStreamControllerFromUnderlyingSource( ) { const controller: ReadableByteStreamController = Object.create(ReadableByteStreamController.prototype); - let startAlgorithm: () => void | PromiseLike = () => undefined; - let pullAlgorithm: () => Promise = () => promiseResolvedWith(undefined); - let cancelAlgorithm: (reason: any) => Promise = () => promiseResolvedWith(undefined); + let startAlgorithm: () => void | PromiseLike; + let pullAlgorithm: () => Promise; + let cancelAlgorithm: (reason: any) => Promise; if (underlyingByteSource.start !== undefined) { startAlgorithm = () => underlyingByteSource.start!(controller); + } else { + startAlgorithm = () => undefined; } if (underlyingByteSource.pull !== undefined) { pullAlgorithm = () => underlyingByteSource.pull!(controller); + } else { + pullAlgorithm = () => promiseResolvedWith(undefined); } if (underlyingByteSource.cancel !== undefined) { cancelAlgorithm = reason => underlyingByteSource.cancel!(reason); + } else { + cancelAlgorithm = () => promiseResolvedWith(undefined); } const autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; diff --git a/src/lib/readable-stream/default-controller.ts b/src/lib/readable-stream/default-controller.ts index 7f1d200..8910049 100644 --- a/src/lib/readable-stream/default-controller.ts +++ b/src/lib/readable-stream/default-controller.ts @@ -184,9 +184,12 @@ function ReadableStreamDefaultControllerCallPullIfNeeded(controller: ReadableStr controller._pullAgain = false; ReadableStreamDefaultControllerCallPullIfNeeded(controller); } + + return null; }, e => { ReadableStreamDefaultControllerError(controller, e); + return null; } ); } @@ -359,9 +362,11 @@ export function SetUpReadableStreamDefaultController(stream: ReadableStream { ReadableStreamDefaultControllerError(controller, r); + return null; } ); } @@ -374,18 +379,24 @@ export function SetUpReadableStreamDefaultControllerFromUnderlyingSource( ) { const controller: ReadableStreamDefaultController = Object.create(ReadableStreamDefaultController.prototype); - let startAlgorithm: () => void | PromiseLike = () => undefined; - let pullAlgorithm: () => Promise = () => promiseResolvedWith(undefined); - let cancelAlgorithm: (reason: any) => Promise = () => promiseResolvedWith(undefined); + let startAlgorithm: () => void | PromiseLike; + let pullAlgorithm: () => Promise; + let cancelAlgorithm: (reason: any) => Promise; if (underlyingSource.start !== undefined) { startAlgorithm = () => underlyingSource.start!(controller); + } else { + startAlgorithm = () => undefined; } if (underlyingSource.pull !== undefined) { pullAlgorithm = () => underlyingSource.pull!(controller); + } else { + pullAlgorithm = () => promiseResolvedWith(undefined); } if (underlyingSource.cancel !== undefined) { cancelAlgorithm = reason => underlyingSource.cancel!(reason); + } else { + cancelAlgorithm = () => promiseResolvedWith(undefined); } SetUpReadableStreamDefaultController( diff --git a/src/lib/readable-stream/pipe.ts b/src/lib/readable-stream/pipe.ts index fac5ea1..05efac8 100644 --- a/src/lib/readable-stream/pipe.ts +++ b/src/lib/readable-stream/pipe.ts @@ -132,6 +132,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, } else { shutdown(true, storedError); } + return null; }); // Errors must be propagated backward @@ -141,6 +142,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, } else { shutdown(true, storedError); } + return null; }); // Closing must be propagated forward @@ -150,6 +152,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, } else { shutdown(); } + return null; }); // Closing must be propagated backward @@ -177,7 +180,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, function isOrBecomesErrored(stream: ReadableStream | WritableStream, promise: Promise, - action: (reason: any) => void) { + action: (reason: any) => null) { if (stream._state === 'errored') { action(stream._storedError); } else { @@ -185,7 +188,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, } } - function isOrBecomesClosed(stream: ReadableStream | WritableStream, promise: Promise, action: () => void) { + function isOrBecomesClosed(stream: ReadableStream | WritableStream, promise: Promise, action: () => null) { if (stream._state === 'closed') { action(); } else { @@ -205,12 +208,13 @@ export function ReadableStreamPipeTo(source: ReadableStream, doTheRest(); } - function doTheRest() { + function doTheRest(): null { uponPromise( action(), () => finalize(originalIsError, originalError), newError => finalize(true, newError) ); + return null; } } @@ -227,7 +231,7 @@ export function ReadableStreamPipeTo(source: ReadableStream, } } - function finalize(isError?: boolean, error?: any) { + function finalize(isError?: boolean, error?: any): null { WritableStreamDefaultWriterRelease(writer); ReadableStreamReaderGenericRelease(reader); @@ -239,6 +243,8 @@ export function ReadableStreamPipeTo(source: ReadableStream, } else { resolve(undefined); } + + return null; } }); } diff --git a/src/lib/readable-stream/tee.ts b/src/lib/readable-stream/tee.ts index 0125764..5b100c9 100644 --- a/src/lib/readable-stream/tee.ts +++ b/src/lib/readable-stream/tee.ts @@ -166,6 +166,7 @@ export function ReadableStreamDefaultTee(stream: ReadableStream, if (!canceled1 || !canceled2) { resolveCancelPromise(undefined); } + return null; }); return [branch1, branch2]; @@ -192,13 +193,14 @@ export function ReadableByteStreamTee(stream: ReadableByteStream): [ReadableByte function forwardReaderError(thisReader: ReadableStreamReader) { uponRejection(thisReader._closedPromise, r => { if (thisReader !== reader) { - return; + return null; } ReadableByteStreamControllerError(branch1._readableStreamController, r); ReadableByteStreamControllerError(branch2._readableStreamController, r); if (!canceled1 || !canceled2) { resolveCancelPromise(undefined); } + return null; }); } diff --git a/src/lib/transform-stream.ts b/src/lib/transform-stream.ts index 7fd6188..ab3fe4e 100644 --- a/src/lib/transform-stream.ts +++ b/src/lib/transform-stream.ts @@ -371,22 +371,26 @@ function SetUpTransformStreamDefaultControllerFromTransformer(stream: Tran transformer: ValidatedTransformer) { const controller: TransformStreamDefaultController = Object.create(TransformStreamDefaultController.prototype); - let transformAlgorithm = (chunk: I): Promise => { - try { - TransformStreamDefaultControllerEnqueue(controller, chunk as unknown as O); - return promiseResolvedWith(undefined); - } catch (transformResultE) { - return promiseRejectedWith(transformResultE); - } - }; - - let flushAlgorithm: () => Promise = () => promiseResolvedWith(undefined); + let transformAlgorithm: (chunk: I) => Promise; + let flushAlgorithm: () => Promise; if (transformer.transform !== undefined) { transformAlgorithm = chunk => transformer.transform!(chunk, controller); + } else { + transformAlgorithm = chunk => { + try { + TransformStreamDefaultControllerEnqueue(controller, chunk as unknown as O); + return promiseResolvedWith(undefined); + } catch (transformResultE) { + return promiseRejectedWith(transformResultE); + } + }; } + if (transformer.flush !== undefined) { flushAlgorithm = () => transformer.flush!(controller); + } else { + flushAlgorithm = () => promiseResolvedWith(undefined); } SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); diff --git a/src/lib/writable-stream.ts b/src/lib/writable-stream.ts index 2f94c38..4c4c3a0 100644 --- a/src/lib/writable-stream.ts +++ b/src/lib/writable-stream.ts @@ -447,10 +447,12 @@ function WritableStreamFinishErroring(stream: WritableStream) { () => { abortRequest._resolve(); WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return null; }, (reason: any) => { abortRequest._reject(reason); WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return null; }); } @@ -1081,11 +1083,13 @@ function SetUpWritableStreamDefaultController(stream: WritableStream, assert(stream._state === 'writable' || stream._state === 'erroring'); controller._started = true; WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + return null; }, r => { assert(stream._state === 'writable' || stream._state === 'erroring'); controller._started = true; WritableStreamDealWithRejection(stream, r); + return null; } ); } @@ -1096,22 +1100,30 @@ function SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream: Writa sizeAlgorithm: QueuingStrategySizeCallback) { const controller = Object.create(WritableStreamDefaultController.prototype); - let startAlgorithm: () => void | PromiseLike = () => undefined; - let writeAlgorithm: (chunk: W) => Promise = () => promiseResolvedWith(undefined); - let closeAlgorithm: () => Promise = () => promiseResolvedWith(undefined); - let abortAlgorithm: (reason: any) => Promise = () => promiseResolvedWith(undefined); + let startAlgorithm: () => void | PromiseLike; + let writeAlgorithm: (chunk: W) => Promise; + let closeAlgorithm: () => Promise; + let abortAlgorithm: (reason: any) => Promise; if (underlyingSink.start !== undefined) { startAlgorithm = () => underlyingSink.start!(controller); + } else { + startAlgorithm = () => undefined; } if (underlyingSink.write !== undefined) { writeAlgorithm = chunk => underlyingSink.write!(chunk, controller); + } else { + writeAlgorithm = () => promiseResolvedWith(undefined); } if (underlyingSink.close !== undefined) { closeAlgorithm = () => underlyingSink.close!(); + } else { + closeAlgorithm = () => promiseResolvedWith(undefined); } if (underlyingSink.abort !== undefined) { abortAlgorithm = reason => underlyingSink.abort!(reason); + } else { + abortAlgorithm = () => promiseResolvedWith(undefined); } SetUpWritableStreamDefaultController( @@ -1217,9 +1229,11 @@ function WritableStreamDefaultControllerProcessClose(controller: WritableStreamD sinkClosePromise, () => { WritableStreamFinishInFlightClose(stream); + return null; }, reason => { WritableStreamFinishInFlightCloseWithError(stream, reason); + return null; } ); } @@ -1246,12 +1260,14 @@ function WritableStreamDefaultControllerProcessWrite(controller: WritableStre } WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + return null; }, reason => { if (stream._state === 'writable') { WritableStreamDefaultControllerClearAlgorithms(controller); } WritableStreamFinishInFlightWriteWithError(stream, reason); + return null; } ); }