UNPKG

1.81 kBPlain TextView Raw
1export function delayedPromise(delay: number): Promise<void> {
2 return new Promise(resolve => setTimeout(resolve, delay));
3}
4
5export function timeoutPromise<T>(promise: Promise<T>, ms: number, message = `timed out after ${ms}ms`): Promise<T> {
6 return new Promise(function (resolve, reject) {
7 setTimeout(() => reject(new Error(message)), ms);
8 promise.then(resolve, reject);
9 });
10}
11
12export interface RetryPromiseOptions {
13 interval: number;
14 retries: number;
15 timeout?: number;
16 timeoutMessage?: string;
17}
18
19const never: Promise<any> = new Promise(() => void 0);
20
21export async function retryPromise<T>(promiseProvider: () => Promise<T>,
22 {interval, retries, timeout, timeoutMessage = `timed out after ${timeout}ms`}: RetryPromiseOptions): Promise<T> {
23 if (!timeout && !retries) {
24 return await promiseProvider();
25 }
26 if (timeout && timeout <= retries * interval) {
27 return Promise.reject(`timeout (${timeout}ms) must be greater than retries (${retries}) times interval (${interval}ms)`)
28 }
29 const raceWithTimeout = [never, never];
30 if (timeout) {
31 raceWithTimeout[1] = delayedPromise(timeout).then(() => Promise.reject(new Error(timeoutMessage)));
32 }
33 let iterations = retries ? retries + 1 : Number.MAX_SAFE_INTEGER;
34 let lastError: Error | null = null;
35 while (iterations-- > 0) {
36 try {
37 raceWithTimeout[0] = promiseProvider();
38 return await Promise.race(raceWithTimeout);
39 } catch (e) {
40 if (e.message === timeoutMessage) {
41 throw lastError || e;
42 }
43 lastError = e;
44 }
45 await new Promise(resolve => setTimeout(resolve, interval));
46 }
47 throw lastError || new Error(timeoutMessage);
48}