xaa
Version:
async/await/Promise helpers - delay, defer, timeout, each, map, filter
304 lines (303 loc) • 9.43 kB
TypeScript
/**
* @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>;