UNPKG

xaa

Version:

async/await/Promise helpers - delay, defer, timeout, each, map, filter

304 lines (303 loc) 9.43 kB
/** * @packageDocumentation * @module index */ type Consumer<T> = (item: T, index?: number) => unknown; type FuncProducer<T> = () => T | Promise<T>; type Producer<T> = Promise<T> | FuncProducer<T>; type Predicate<T> = (item: T, index?: number) => boolean | Promise<boolean>; /** * check if something is a promise * * @param p * @returns true or false */ export declare function isPromise<T>(p: any): p is Promise<T>; /** * Defer object for fulfilling a promise later in other events * * To use, use `xaa.makeDefer` or its alias `xaa.defeer`. * */ export declare class Defer<T> { /** * construct Defer * * @param ThePromise optional promise constructor */ constructor(ThePromise?: PromiseConstructor); /** The promise object for the defer */ promise: Promise<T>; /** resolve the defered promise */ resolve: (result?: T) => void; /** reject the deferred promise */ reject: (reason?: any) => void; /** * node.js callback for the deferred promise * * @param err - error * @param args - result * @returns nothing */ done: (err: Error, ...args: any[]) => void; } /** * Create a promise Defer object * * Sample: * * ```js * async function waitEvent() { * const defer = xaa.makeDefer(); * someThing.on("event", (data) => defer.resolve(data)) * return defer.promise; * } * ``` * * @param ThePromise - optional Promise constructor. * @returns Defer instance */ export declare function makeDefer<T>(ThePromise?: PromiseConstructor): Defer<T>; export { makeDefer as defer }; /** * The error xaa.timeout will throw if operation timed out */ export declare class TimeoutError extends Error { constructor(msg: string); } /** * delay some milliseconds and then return `valOrFunc` * * Sample: * * ```js * await xaa.delay(500); * await xaa.delay(500, "Result"); * await xaa.delay(500, () => "Result"); * ``` * * @param delayMs - number milliseconds to delay * @param valOrFunc - the value to return. If it's a function, call it to get the value. * It can be an async function. * @returns `valOrFunc` or its returned value if it's a function. */ export declare function delay(delayMs: number): Promise<void>; export declare function delay<T = void>(delayMs: number, valOrFunc: T): Promise<T>; type Task<T> = Promise<T> | (() => Promise<T>); type Tasks<T extends readonly any[]> = { readonly [P in keyof T]: Task<T[P]>; }; type Runnable<T> = T extends readonly any[] ? Tasks<T> : Task<T>; type TimeoutRunnerOptions = { TimeoutError: typeof TimeoutError; Promise: PromiseConstructor; }; /** * TimeoutRunner for running tasks (promises) with a timeout * * Please use `xaa.timeout` or `xaa.runTimeout` APIs instead. */ export declare class TimeoutRunner<T> { /** * constructor * @param maxMs - number of milliseconds to allow tasks to run * @param rejectMsg - message to reject with when timeout triggers * @param options - TimeoutRunnerOptions */ constructor(maxMs: number, rejectMsg: string, options: TimeoutRunnerOptions); /** * message to reject with when timeout triggers */ private defer; /** setTimeout handle */ private timeout; /** * check if runner has failed with error * * @returns has error flag */ hasError(): boolean; /** * check if runner has finished with result * * @returns has result flag */ hasResult(): boolean; /** * Run tasks * * @param tasks - Promise or function that returns Promise, or array of them. * @returns Promise to wait for tasks to complete, or timeout error. */ run<U extends Runnable<T>>(tasks: U): Promise<T | T[]>; /** * Cancel the operation and reject with msg * * @param msg - cancel message */ cancel(msg?: string): void; /** Explicitly clear the setTimeout handle */ clear(): void; /** * Check if runner is done * * @returns is done flag */ isDone(): boolean; /** number of milliseconds to allow tasks to run */ maxMs: number; /** message to reject with if operation timed out */ rejectMsg: string; /** the error if running failed */ error?: Error; /** the result from running tasks */ result?: T | T[]; /** Promise constructor */ ThePromise: PromiseConstructor; /** TimeoutError constructor */ TimeoutError: typeof TimeoutError; } /** * Create a TimeoutRunner to run tasks (promises) with timeout * * Sample: * * ```js * await xaa.timeout(1000, "timeout fetching data").run(() => fetch(url)) * ``` * * with promises: * * ```js * await xaa.timout(1000).run([promise1, promise2]) * ``` * * @param maxMs - number of milliseconds to allow tasks to run * @param rejectMsg - message to reject with when timeout triggers * @returns TimeoutRunner object */ export declare function timeout<T>(maxMs: number, rejectMsg?: string, options?: TimeoutRunnerOptions): TimeoutRunner<T>; /** * Calls `timeout(maxMs, rejectMsg).run(tasks)` * * @param tasks - Promise or function or array of them * @param maxMs - milliseconds to wait for the tasks to fulfill * @param rejectMsg - message to reject with if operation timed out * @returns promise results from all tasks */ export declare function runTimeout<T>(tasks: Task<T>, maxMs: number, rejectMsg?: string, options?: TimeoutRunnerOptions): Promise<T>; export declare function runTimeout<T extends readonly any[]>(tasks: Tasks<T>, maxMs: number, rejectMsg?: string, options?: TimeoutRunnerOptions): Promise<T[]>; /** * The error xaa.map will throw if something went wrong. * * Contains a partial field for result mapped before error was encountered. */ export interface MapError<T> extends Error { /** the result that has been mapped before error was encountered */ partial: T[]; } /** options for xaa.map */ export type MapOptions = { /** number of items to map concurrently */ concurrency: number; /** the this passed to the map callback */ thisArg?: any; }; /** context from xaa.map to the mapper callback */ export type MapContext<T> = { /** * indicate if another map operation during concurrent map has failed * Mapping should observe this flag whenever possible and avoid continuing * if it makes sense. */ failed?: boolean; /** * the original array that's passed to xaa.map */ array: readonly T[]; /** * During concurrent map, if any mapper failed, this allow other inflight * map functions to assert that no failure has occurred, else stop. */ assertNoFailure: () => void; }; type Awaited<T> = T extends PromiseLike<infer T2> ? { 0: Awaited<T2>; 1: T2; }[T2 extends PromiseLike<any> ? 0 : 1] : T; /** * callback function for xaa.map to map the value. * * @param value value to map * @param index index of the value in the array * @param context MapContext * @returns any or a promise */ export type MapFunction<T, O> = (value: Awaited<T>, index: number, context: MapContext<T>) => O | Promise<O>; export declare function mapSeries<T, O>(array: readonly T[], func?: MapFunction<T, O>, options?: MapOptions): Promise<O[]>; /** * async map array with concurrency * * - intended to be similar to `bluebird.map` * * @param array array to map, if any item is promise-like, it will be resolved first. * @param func - callback to map values from the array * @param options - MapOptions * @returns promise with mapped result */ export declare function map<T, O>(array: readonly T[], func?: MapFunction<T, O>, options?: MapOptions): Promise<O[]>; /** * async version of array.forEach * - iterate through array and await call func with each element and index * * Sample: * * ```js * await xaa.each([1, 2, 3], async val => await xaa.delay(val)) * ``` * * @param array array to each * @param func callback for each */ export declare function each<T>(array: readonly T[], func: Consumer<T>): Promise<T[]>; /** * async filter array * * Sample: * * ```js * await xaa.filter([1, 2, 3], async val => await validateResult(val)) * ``` * * Beware: concurrency is fixed to 1. * * @param array array to filter * @param func callback for filter * @returns filtered result */ export declare function filter<T>(array: readonly T[], func: Predicate<T>): Promise<any[]>; type ValueOrErrorHandler<T> = T extends Function ? never : T | Promise<T> | ((err?: Error) => T | Promise<T>); /** * try to: * - await a promise * - call and await function that returns a promise * * If exception occur, then return `valOrFunc` * * - if `valOrFunc` is a function, then return `valOrFunc(err)` * * @param funcOrPromise function or promise to try * @param valOrFunc value, or callback to get value, to return if `func` throws * @returns result, `valOrFunc`, or `valOrFunc(err)`. */ export declare function tryCatch<T, TAlt>(funcOrPromise: Producer<T>, valOrFunc?: ValueOrErrorHandler<TAlt>): Promise<T | TAlt>; export { tryCatch as try }; /** * Wrap the calling of a function into async/await (promise) context * - intended to be similar to `bluebird.try` * * @param func function to wrap in async context * @param args arguments to pass to `func` * @returns result from `func` */ export declare function wrap<T, F extends (...args: any[]) => T>(func: F, ...args2: Parameters<F>): Promise<T>;