xref: /expo/packages/@expo/cli/src/utils/delay.ts (revision dad749c2)
1import { CommandError } from './errors';
2
3/** Await for a given duration of milliseconds. */
4export function delayAsync(timeout: number): Promise<void> {
5  return new Promise((resolve) => setTimeout(resolve, timeout));
6}
7
8/** Wait for a given action to return a truthy value. */
9export async function waitForActionAsync<T>({
10  action,
11  interval = 100,
12  maxWaitTime = 20000,
13}: {
14  action: () => T | Promise<T>;
15  interval?: number;
16  maxWaitTime?: number;
17}): Promise<T> {
18  let complete: T;
19  const start = Date.now();
20  do {
21    const actionStartTime = Date.now();
22    complete = await action();
23
24    const actionTimeElapsed = Date.now() - actionStartTime;
25    const remainingDelayInterval = interval - actionTimeElapsed;
26    if (remainingDelayInterval > 0) {
27      await delayAsync(remainingDelayInterval);
28    }
29    if (Date.now() - start > maxWaitTime) {
30      break;
31    }
32  } while (!complete);
33
34  return complete;
35}
36
37/** Resolves a given function or rejects if the provided timeout is passed. */
38export function resolveWithTimeout<T>(
39  action: () => Promise<T>,
40  {
41    timeout,
42    errorMessage,
43  }: {
44    /** Duration in milliseconds to wait before asserting a timeout. */
45    timeout: number;
46    /** Optional error message to use in the assertion. */
47    errorMessage?: string;
48  }
49): Promise<T> {
50  return new Promise((resolve, reject) => {
51    setTimeout(() => {
52      reject(new CommandError('TIMEOUT', errorMessage));
53    }, timeout);
54    action().then(resolve, reject);
55  });
56}
57