import {Deferred} from "./deferred"; import {PromiseMap} from "./promiseMap"; import {PromiseFilter} from "./promiseFilter"; import {PromiseSome} from "./promiseSome"; import { IterateFunction, Resolvable} from "./interfaces"; import {Time} from "../time"; import {PromiseCreate} from "./promiseCreate"; import {IRetry} from "../types/types"; export class Promises { public static delay(delay: number): Promise { return new Promise(resolve => setTimeout(resolve, delay)); } public static map(iterable: Resolvable>>, mapper: IterateFunction, options: { concurrency: number } = {concurrency: Infinity}): Promise { return PromiseMap.map(iterable, mapper, options); } public static props(props: object & { [K in keyof T]: Resolvable }, options: { concurrency: number } = {concurrency: Infinity}): Promise { const keys = Object.keys(props); const values = Object.values(props); return Promises.map(values, (item) => item, {concurrency: options.concurrency}) .then(resolved => { const res: { [K in keyof T]: T[K] } = {} as any; for (let i = 0, len = keys.length; i < len; i++) { res[keys[i]] = resolved[i]; } return res }) } public static filter(iterable: Resolvable>>, filterer: IterateFunction, options: { concurrency: number } = {concurrency: Infinity}): Promise { return PromiseFilter.filter(iterable, filterer, options) } public static fromCallback(resolver: (callback: (err: any, result?: T) => void) => void): Promise { return new Promise((resolve, reject) => { resolver((err, data) => { if (err == null) { resolve(data); } else { reject(err); } }) }) } public static defer(): Deferred { return new Deferred(); } public static async to(promise: Promise): Promise<[K, T?]> { try { let result = await promise; return [null, result] as [K, T] } catch (e) { return [e] as [K, T?]; } } public static async toNull(promise: Promise): Promise { try { let result = await promise; return result } catch (e) { return null; } } public static allSettled(promises: Promise[]): Promise<({ status: "fulfilled"; value: T; } | { status: "rejected"; reason: any; })[]> { let settled = []; for (let i = 0; i < promises.length; i++) { let promise = promises[i] .then(value => ({status: "fulfilled", value})) .catch(reason => ({status: "rejected", reason})); settled.push(promise); } return Promise.all(settled); } public static async allSettledSpread(promises: Promise[]): Promise<([T[], any[]])> { let fulfilled: T[] = [], rejected: any[] = []; let results = await Promises.allSettled(promises); for (let i = 0; i < results.length; i++) { let item = results[i]; if (item.status == "fulfilled") { fulfilled.push(item.value) } else { rejected.push(item.reason) } } return [fulfilled, rejected] } public static some(promises: Promise[], opts: { counter?: number } = {}): Promise<({ status: "fulfilled"; value: T; } | { status: "rejected"; reason: any; })[]> { return PromiseSome.some(promises, opts); } public static someRejected(promises: Promise[], opts: { counter?: number, fn?: (value: T) => boolean } = {}): Promise<({ status: "rejected"; reason: any; })[]> { return PromiseSome.someRejected(promises, opts); } public static someResolved(promises: Promise[], opts: { counter?: number, fn?: (value: T) => boolean } = {}): Promise<({ status: "fulfilled"; value: T; })[]> { return PromiseSome.someResolved(promises, opts); } public static isPromise(obj: any): boolean { return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function' && typeof obj.catch === 'function'; } public static timeout(promise: Promise, timeout: number): Promise { return Promises.promiseTimeout(promise, timeout) } public static async retry(fn: () => Promise, options: (number | IRetry) = 1, retryCount: number = 0): Promise { let [err, result] = await Promises.to(fn()); if (err == null) { return result } if (typeof options == "number") { options = {retires: options} } retryCount++; if (retryCount > options.retires) { throw err; } let delay = Time.calcBackOff(retryCount, options); if (delay) { await Promises.delay(delay); } return Promises.retry(fn, options, retryCount); } public static promiseTimeout(promise: Promise, timeout: number): Promise { return new Promise((resolve, reject) => { let interval = setTimeout(() => reject(new Error("promise timeout")), timeout); promise .then(resolve) .catch(reject) .finally(() => clearTimeout(interval)) }) } public static create(fn: () => Promise): PromiseCreate { return new PromiseCreate(fn) } }