UNPKG

wait-utils

Version:

A modern, zero-dependency wait / timing utility toolkit for JavaScript and TypeScript.

247 lines (238 loc) 8.33 kB
/** * Error thrown when an operation is aborted via an `AbortSignal`. * * This error is used in asynchronous operations * to indicate that the caller explicitly cancelled * the request by invoking `AbortController.abort()`. */ declare class AbortError extends DOMException { constructor(message?: string); } /** * Error thrown when an operation exceeds its allowed time limit. * * This error is used in asynchronous operations to indicate * that the operation took too long to complete and was * terminated based on a timeout setting. */ declare class TimeoutError extends DOMException { constructor(message?: string); } /** * A hook invoked after each successful callback execution in {@link poll}. * * Can be used for logging, adjusting the next delay, or stopping the wait loop. * * This is skipped if the callback stops the wait or throws. * * @param context - The current {@link PollContext}. */ type AfterPollCallback<T = unknown> = (context: PollContext<T>) => unknown | Promise<unknown>; /** * The main function invoked at each iteration in {@link poll}. * * This function performs the primary asynchronous operation. * To stop further attempts, set `context.stop = true`. * * @param context - The current {@link PollContext}. * * @returns A result value, or a Promise that resolves to one. */ type PollCallback<T = unknown, R = unknown> = (context: PollContext<T>) => R | Promise<R>; /** * Context object in {@link poll}. */ interface PollContext<T = unknown> { /** * The current attempt number, starting from `1` and incremented automatically. * @readonly */ readonly attempt: number; /** * The delay (in milliseconds) before the next attempt. * * Can be updated dynamically to implement backoff, jitter, etc. */ delay?: number | null; /** * Set to `true` to stop further attempts. */ stop?: boolean; /** * User-provided data. * * Useful for sharing state or configuration across attempts. */ userData?: T; } /** * Configuration options for {@link poll}. */ interface PollOptions<T = unknown> { /** * A function to run after each poll attempt. * * Can be used to log results, inspect attempt state, or modify future behavior. */ afterPoll?: AfterPollCallback<T>; /** * The delay (in milliseconds) between subsequent attempts. * * Can be changed dynamically via {@link PollContext.delay | context.delay}. */ delay?: number | null; /** * The delay (in milliseconds) before the first attempt. * If not specified, falls back to {@link delay}. */ initialDelay?: number | null; /** * An {@link AbortSignal} to cancel the wait loop. * * If triggered, the function throws an `AbortError`. */ signal?: AbortSignal; /** * The maximum total duration (in milliseconds) to wait before timing out. * * If exceeded, the function throws a `TimeoutError`. */ timeout?: number; /** * User-provided data. * * Useful for sharing state or configuration across attempts. */ userData?: T; } /** * Repeatedly invokes a callback function until it succeeds, is stopped, aborted, or times out. * * After each successful callback execution, an optional {@link PollOptions.afterPoll} * hook is invoked. You can control retry timing by updating `context.delay` or exit * early by setting `context.stop = true`. * * @typeParam T - The shape of the user data passed through the context. * @typeParam R - The return type of the callback function. * * @param callback - The function to invoke on each attempt. * @param options - Optional configuration to control timing, retries, and cancellation. * * @returns The last value returned by the callback. * * @throws `AbortError` if the operation is cancelled using `signal`. * @throws `TimeoutError` if the total wait duration exceeds `timeout`. */ declare function poll<T, R>(callback: PollCallback<T, R>, options?: PollOptions<T>): Promise<R>; /** * Context object provided to the {@link setIntervalAsync} callback. */ interface IntervalContext { /** * The delay in milliseconds before the next tick. * Defaults to the initial delay provided to {@link setIntervalAsync}. * The callback can modify this property to change intervals dynamically. */ delay?: number; /** * When set to `true`, the inverval is stopped. */ stop?: boolean; /** * The tick counter, starting at `1` and incremented automatically. * @readonly * @remarks This property cannot be modified by the callback. */ readonly tickCount: number; } /** * Asynchronously calls a callback repeatedly at a given interval. * * Internally uses `setTimeout`, so interval drift may occur. * * @param callback - Invoked on each tick. Receives a mutable {@link IntervalContext} object, * allowing the callback to change delay dynamically or stop the interval. * @param delay - The delay in milliseconds between invocations. * Can be changed dynamically via `context.delay`. * @param signal - An `AbortSignal` which can cancel the interval. * * @returns A promise that: * - resolves when `context.stop` is set to `true` inside the callback (graceful termination), * - rejects with `signal.reason` if the signal aborts, * - rejects if the callback throws or rejects. * * @example * ```ts * let count = 0; * setIntervalAsync(ctx => { * console.log("tick", ++count); * ctx.stop = count >= 5; * }, 1000).then(() => { * console.log("Completed after 5 ticks"); * }); * ``` */ declare function setIntervalAsync(callback: (context: IntervalContext) => unknown | Promise<unknown>, delay?: number, signal?: AbortSignal): Promise<void>; /** * Asynchronously delays execution for the specified duration. * * @param delay - The number of milliseconds to wait. * @param signal - An `AbortSignal` that can cancel the wait early. * * @returns A promise that resolves after the delay, or rejects with * the `signal.reason` if `signal` is aborted before timeout. * * @example * ```ts * // Basic usage * await setTimeoutAsync(1000); * * // Abortable usage * const controller = new AbortController(); * setTimeoutAsync(2000, controller.signal) * .catch(reason => console.log('Aborted due to', reason)); * controller.abort('Timeout canceled'); * ``` */ declare function setTimeoutAsync(delay?: number, signal?: AbortSignal): Promise<void>; /** * Rejects with a `TimeoutError` after the specified delay, * unless cancelled by an `AbortSignal`. * * @param delay - The number of milliseconds to wait before timing out. * @param signal - Optional `AbortSignal` to cancel the timeout. * * @returns A promise that: * - resolves if the signal is aborted before the delay * - rejects with a `TimeoutError` if the delay completes * - rethrows an error if an unexpected rejection occurs */ declare function timeout(delay?: number | null, signal?: AbortSignal): Promise<void>; /** * Waits for the specified number of milliseconds. * * Supports cancellation via an `AbortSignal`. * * @param delay - The number of milliseconds to wait. * @param signal - Optional `AbortSignal` to cancel the wait early. * * @returns A promise that: * - resolves after the delay * - rejects with the `AbortSignal.reason` if cancelled before the delay */ declare function wait(delay?: number | null, signal?: AbortSignal): Promise<void>; /** * Waits until the specified time is reached. * * @param timestamp - Target time: * - If a {@link Date}, relative to {@link Date.now}. * - If a `number`, relative to {@link performance.now}. * * @param signal - Optional `AbortSignal` to cancel the wait early. * * @returns A promise that: * - resolves when the current time is at or past the target time * - rejects with the signal’s reason if cancelled before the target */ declare function waitUntil(timestamp?: Date | number | null, signal?: AbortSignal): Promise<void>; export { AbortError, type AfterPollCallback, type IntervalContext, type PollCallback, type PollContext, type PollOptions, TimeoutError, poll, setIntervalAsync, setTimeoutAsync, timeout, wait, waitUntil };