aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/oncePromise.ts
blob: f6ce775f82bb5ef3f107ec7961abec14f1adae7d (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
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>, timeout = -1) => {
  let getPromise = (): Promise<T> => {
    const oldGetPromise = getPromise,
      promise = ensurePromise(create()).catch((e) => {
        getPromise = oldGetPromise;
        throw e;
      }),
      expires = timeout > 0 ? performance.now() + timeout : 0;
    return (getPromise = expires
      ? ((() =>
          performance.now() > expires
            ? oldGetPromise()
            : promise) as () => Promise<T>)
      : () => promise)();
  };
  return () => getPromise();
};
export default oncePromise;