Source: app/util/pollUtils.js

export class TimeoutError extends Error {}

/**
 * @param {Function} pollFunction - function that should return a promise
 * @param {Function} predicate - function to check whether race condition was met during polling
 * @param {number} timeout - optional timeout or infinite polling
 * @param {number} interval
 *
 * @example
 *
 * pollApi(
 *   () => Promise.resolve(true), // pollFunction
 *   response => !!response, // predicate
 * ).then(console.log); // `true`
 *
 */
export const pollApi = (pollFunction, predicate, interval = 150, timeout = null) => {
  const checkCondition = (resolve, reject) => {
    let pollTimeout = null;
    let timeoutTimeout = null;

    const pollHandler = () =>
      pollFunction().then(response => {
        // If the condition is met, we're done!
        if (predicate(response)) {
          clearTimeout(timeout ? timeoutTimeout : pollTimeout);
          resolve(response);

          return;
        }

        pollTimeout = setTimeout(pollHandler, interval);
      });

    // If the promise has not been resolved within the timeout reject it
    if (timeout) {
      timeoutTimeout = setTimeout(() => {
        clearTimeout(pollTimeout);
        reject(new TimeoutError());
      }, timeout);
    }

    // Start first poll
    pollHandler();
  };

  return new Promise(checkCondition);
};