| export type PollOptions<T> = { | |
| intervalMs: number | |
| immediate?: boolean | |
| shouldStop?: (value: T) => boolean | |
| signal?: AbortSignal | |
| } | |
| function sleep(ms: number, signal?: AbortSignal) { | |
| if (ms <= 0) return Promise.resolve() | |
| return new Promise<void>((resolve, reject) => { | |
| const timer = window.setTimeout(() => { | |
| signal?.removeEventListener('abort', onAbort) | |
| resolve() | |
| }, ms) | |
| function onAbort() { | |
| window.clearTimeout(timer) | |
| reject(new DOMException('Aborted', 'AbortError')) | |
| } | |
| if (signal) { | |
| if (signal.aborted) return onAbort() | |
| signal.addEventListener('abort', onAbort, { once: true }) | |
| } | |
| }) | |
| } | |
| export async function poll<T>(fn: () => Promise<T>, options: PollOptions<T>) { | |
| const { intervalMs, immediate = true, shouldStop, signal } = options | |
| if (!immediate) await sleep(intervalMs, signal) | |
| while (true) { | |
| if (signal?.aborted) throw new DOMException('Aborted', 'AbortError') | |
| const value = await fn() | |
| if (shouldStop?.(value)) return value | |
| await sleep(intervalMs, signal) | |
| } | |
| } | |