UNPKG

race-cancellation

Version:

Utilities for using Promise.race([task, cancellation]) for async/await code.

62 lines 2.22 kB
// we are casting the sentinel value to a unique symbol // to get === union narrowing const sentinelValue = { toString: () => "[cancel sentinel]", }; /** * Create a {@link RaceCancelFn} function. * * @param isCancelled - a function that returns whether or not we are currently cancelled * @param executor - a callback to resolve the cancellation * @param cancelReason - an optional reason for the cancellation * @public */ export default function newRaceCancel(isCancelled, executor, cancelReason) { // the async cancel executor should only run 0 or 1 times const memoizedAsyncCancel = memoizeAsyncCancel(isCancelled, executor); return async (asyncFnOrPromise) => throwIfCancelled(await raceCancel(asyncFnOrPromise, isCancelled, memoizedAsyncCancel), cancelReason); } function raceCancel(asyncFnOrPromise, isCancelled, memoizedAsyncCancel) { return typeof asyncFnOrPromise === "function" ? isCancelled() ? memoizedAsyncCancel() : Promise.race([asyncFnOrPromise(), memoizedAsyncCancel()]) : Promise.race([asyncFnOrPromise, memoizedAsyncCancel()]); } function throwIfCancelled(result, cancelReason) { if (result === sentinelValue) { throw intoCancelError(cancelReason); } return result; } function memoizeAsyncCancel(isCancelled, executor) { let promise; return () => { if (promise === undefined) { promise = isCancelled() ? Promise.resolve(sentinelValue) : waitForCancel(executor); } return promise; }; } async function waitForCancel(cancelExecutor) { await new Promise(cancelExecutor); return sentinelValue; } function intoCancelError(cancelReason) { if (typeof cancelReason === "function") { cancelReason = cancelReason(); } if (cancelReason === undefined || typeof cancelReason === "string") { return newCancelError(cancelReason); } return cancelReason; } function newCancelError(message = "The operation was cancelled") { const cancelError = new Error(message); cancelError.name = "CancelError"; cancelError.isCancelled = true; return cancelError; } //# sourceMappingURL=newRaceCancel.js.map