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