File size: 1,067 Bytes
98277cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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)
  }
}