export class AsyncUtils { static async wait(ms: number): Promise { return new Promise(resolve => { setTimeout(() => { resolve(); }, ms); }); } static async runWithRetries(generator: () => Promise, retries = 3, delayBetweenTries = 1000, errorSelector?: (err: any) => boolean) { let lastError: any; if (retries < 1) { retries = 1; } for (let i = 0; i < retries; i++) { try { return await generator(); } catch (err) { if (errorSelector && !errorSelector(err)) { throw err; } lastError = err; if (delayBetweenTries > 0) { await AsyncUtils.wait(delayBetweenTries); } } } throw lastError; } static waitForWithoutTimeout(generator: () => boolean, delay = 100) { return AsyncUtils.waitFor(generator, delay, 0); } static beginTaskTimeNormalization() { return { time: Date.now() }; } static async endTaskTimeNormalization(options: { time: number }, normalizedTime = 500) { const elapsed = Date.now() - options.time; if (elapsed < normalizedTime) { await AsyncUtils.wait(normalizedTime - elapsed) } } static async normalizeTaskTime(task: () => Promise, normalizedTime = 500, ignoreErrors = false): Promise { const time = Date.now(); let error: any; let result: any; try { result = await task(); } catch (err) { error = err; } const elapsed = Date.now() - time; if (elapsed < normalizedTime) { await AsyncUtils.wait(normalizedTime - elapsed) } if (error && !ignoreErrors) { throw error; } return result as T; } static async waitFor(generator: () => boolean, delay = 100, timeout = 15000) { const useTTL = timeout > 0; let ttl = timeout; while (!generator() && (!useTTL || ttl > 0)) { await AsyncUtils.wait(delay); if (ttl > 0) { ttl -= delay; } } if (timeout !== 0 && ttl <= 0) { throw new Error('Timeout'); } return true; } }