UNPKG

@lodestar/utils

Version:

Utilities required across multiple lodestar packages

105 lines 3.29 kB
import { ErrorAborted, TimeoutError } from "./errors.js"; import { sleep } from "./sleep.js"; /** * While promise t is not finished, call function `fn` per `interval` */ export async function callFnWhenAwait(p, fn, interval, signal) { let done = false; const logFn = async () => { while (!done) { await sleep(interval, signal); if (!done) fn(); } }; const t = await Promise.race([p, logFn()]).finally(() => { done = true; }); return t; } /** * Create a deferred promise */ export function defer() { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } /** * Wrap a promise to an object to track the status and value of the promise */ export function wrapPromise(promise) { const startedAt = Date.now(); const result = { promise: promise.then((value) => { result.status = "fulfilled"; result.value = value; result.durationMs = Date.now() - startedAt; return value; }, (reason) => { result.status = "rejected"; result.reason = reason; result.durationMs = Date.now() - startedAt; throw reason; }), status: "pending", }; return result; } /** * Two phased approach for resolving promises: * - first wait `resolveTimeoutMs` or until all promises settle * - then wait `raceTimeoutMs - resolveTimeoutMs` or until at least a single promise resolves * * Returns a list of promise results, see `PromiseResult` */ export async function resolveOrRacePromises(promises, { resolveTimeoutMs, raceTimeoutMs, signal, }) { if (raceTimeoutMs <= resolveTimeoutMs) { throw new Error("Race time must be greater than resolve time"); } const resolveTimeoutError = new TimeoutError(`Given promises can't be resolved within resolveTimeoutMs=${resolveTimeoutMs}`); const raceTimeoutError = new TimeoutError(`Not a any single promise be resolved in given raceTimeoutMs=${raceTimeoutMs}`); const promiseResults = promises.map((p) => wrapPromise(p)); // We intentionally want an array of promises here promises = promiseResults.map((p) => p.promise); try { await Promise.race([ Promise.allSettled(promises), sleep(resolveTimeoutMs, signal).then(() => { throw resolveTimeoutError; }), ]); return promiseResults; } catch (err) { if (err instanceof ErrorAborted) { return promiseResults; } if (err !== resolveTimeoutError) { throw err; } } try { await Promise.race([ Promise.any(promises), sleep(raceTimeoutMs - resolveTimeoutMs, signal).then(() => { throw raceTimeoutError; }), ]); return promiseResults; } catch (err) { if (err instanceof ErrorAborted) { return promiseResults; } if (err !== raceTimeoutError && !(err instanceof AggregateError)) { throw err; } } return promiseResults; } //# sourceMappingURL=promise.js.map