UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

94 lines (93 loc) 3.52 kB
import { RequiredError } from "../error/RequiredError.js"; /** Is a value an asynchronous value implementing a `then()` function. */ export function isAsync(value) { return typeof value === "object" && value !== null && typeof value.then === "function"; } /** Is a value a synchronous value. */ export function notAsync(value) { return !isAsync(value); } /** * Throw the value if it's an async (promised) value. * @returns Synchronous (not promised) value. * @throws Promise if value is an asynchronous (promised) value. */ export function throwAsync(value) { if (isAsync(value)) throw value; return value; } /** Assert an unknown value is synchronous (i.e. does not have a `.then()` method). */ export function assertNotAsync(value) { if (isAsync(value)) throw new RequiredError("Must be synchronous", { received: value, caller: assertNotAsync }); } /** Assert an unknown value is asynchronous (i.e. has a `.then()` method). */ export function assertAsync(value) { if (!isAsync(value)) throw new RequiredError("Must be asynchronous", { received: value, caller: assertAsync }); } /** Assert that an unknown value is a `Promise` */ export function assertPromise(value) { if (!(value instanceof Promise)) throw new RequiredError("Must be promise", { received: value, caller: assertPromise }); } /** Run any queued microtasks now. */ export function runMicrotasks() { // Timeouts are part of the main event queue, and events in the main queue are run _after_ all microtasks complete. return new Promise(resolve => setTimeout(resolve)); } export async function getConcurrent(...promises) { return (await Promise.allSettled(promises)).map(_getFulfilledResult); } function _getFulfilledResult(result) { if (result.status === "rejected") throw result.reason; return result.value; } /** Type of `Promise` with `._resolve()` and `._reject()` methods available. */ export class AbstractPromise extends Promise { // Make `this.then()` create a `Promise` not a `Deferred` // Done with a getter because some implementations implement this with a getter and we need to override it. static get [Symbol.species]() { return Promise; } /** Resolve this promise with a value. */ _resolve; /** Reject this promise with a reason. */ _reject; constructor() { let _resolve; let _reject; super((x, y) => { _resolve = x; _reject = y; }); // biome-ignore lint/style/noNonNullAssertion: This is set inside the executor callback. this._resolve = _resolve; // biome-ignore lint/style/noNonNullAssertion: This is set inside the executor callback. this._reject = _reject; } } /** * Get a deferred to access the `resolve()` and `reject()` functions of a promise. * - See https://github.com/tc39/proposal-promise-with-resolvers/ */ export function getDeferred() { let resolve; let reject; return { promise: new Promise((x, y) => { resolve = x; reject = y; }), // biome-ignore lint/style/noNonNullAssertion: This is set inside the executor callback. resolve: resolve, // biome-ignore lint/style/noNonNullAssertion: This is set inside the executor callback. reject: reject, }; } /** Get a promise that automatically resolves after a delay. */ export function getDelay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }