aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/oncePromise.ts
blob: 6ce6287fd79eb783b7c9260930e66ab770dac341 (plain) (blame)
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
const ensurePromise = <T>(maybePromise: T | PromiseLike<T>): Promise<T> =>
  typeof maybePromise === 'object' &&
  maybePromise !== null &&
  'then' in maybePromise &&
  typeof maybePromise.then === 'function' &&
  'catch' in maybePromise &&
  typeof maybePromise.catch === 'function' &&
  'finally' in maybePromise &&
  typeof maybePromise.finally === 'function'
    ? (maybePromise as Promise<T>)
    : Promise.resolve(maybePromise);
/** Returns a function that caches successful promises until time runs out, and throws away unsuccessful ones */
export const oncePromise = <T>(
  create: () => Promise<T>,
  retries = true,
  timeout = -1
) => {
  let getPromise = (): Promise<T> => {
    const oldGetPromise = getPromise,
      promise = retries
        ? ensurePromise(create()).catch((e) => {
            getPromise = oldGetPromise;
            throw e;
          })
        : ensurePromise(create()),
      expires = timeout > 0 ? performance.now() + timeout : 0;
    return (getPromise = expires
      ? ((() =>
          performance.now() > expires
            ? oldGetPromise()
            : promise) as () => Promise<T>)
      : () => promise)();
  };
  return () => getPromise();
};
export default oncePromise;