@lodestar/utils
Version:
Utilities required across multiple lodestar packages
105 lines • 3.29 kB
JavaScript
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