|
1 |
| -import { timer, delay, from, concatMap, takeWhile, last, raceWith, lastValueFrom, NEVER } from "rxjs"; |
| 1 | +import { concatMap, delay, from, last, lastValueFrom, raceWith, takeWhile, timer, NEVER } from "rxjs"; |
2 | 2 |
|
3 |
| -// Known issues: |
4 |
| -// - the case where `apiFn` returns `false` and `condition(false) === true` is impossible to distinguish from a timeout |
| 3 | +/** |
| 4 | + * Repeatedly calls `apiFn` every `interval` milliseconds, until either `conditionFn` |
| 5 | + * returns `true` or `options.maxTimeout` milliseconds have elapsed. Returns a Promise |
| 6 | + * which resolves to `false` if `options.maxTimout` is reached or the value of `apiFn` |
| 7 | + * which passes the condition otherwise. If no `options.maxTimeout` is specified, it will |
| 8 | + * continue polling indefinitely until a matching value is found, so let's try not to DDOS |
| 9 | + * ourselves. |
| 10 | + * |
| 11 | + * Known issues: |
| 12 | + * - the case where `apiFn` returns `false` and `conditionFn(false) === true` is impossible |
| 13 | + * to distinguish from a timeout, so don't poll for a boolean without first wrapping it |
| 14 | + * with something like `.then(bool => ({ hopefullyUsefulFieldName: bool }))`. |
| 15 | + */ |
5 | 16 | export function pollUntil<ResponseType>(
|
6 | 17 | apiFn: () => Promise<ResponseType>,
|
7 |
| - condition: (res: ResponseType) => boolean, |
| 18 | + conditionFn: (res: ResponseType) => boolean, |
8 | 19 | options: { interval: number; maxTimeout?: number }
|
9 |
| -) { |
| 20 | +): Promise<ResponseType | false> { |
10 | 21 | const { interval, maxTimeout } = options;
|
11 | 22 | const poll$ = timer(0, interval).pipe(
|
12 |
| - concatMap((_) => from(apiFn())), |
13 |
| - takeWhile((result) => !condition(result), true), |
14 |
| - last() |
| 23 | + concatMap((_) => from(apiFn())), // combine all emitted values into a single stream |
| 24 | + takeWhile((result) => !conditionFn(result), true), |
| 25 | + last() // only emit the latest polled value |
15 | 26 | );
|
16 | 27 |
|
17 |
| - const timeout$ = maxTimeout ? from([false]).pipe(delay(maxTimeout)) : NEVER; |
| 28 | + const timeout$ = maxTimeout ? from([false] as Array<false>).pipe(delay(maxTimeout)) : NEVER; |
18 | 29 |
|
19 | 30 | return lastValueFrom(poll$.pipe(raceWith(timeout$)));
|
20 | 31 | }
|
0 commit comments