UNPKG

@kentcdodds/tmp-remix-utils

Version:

This package contains simple utility functions to use with [Remix.run](https://remix.run).

113 lines (112 loc) 2.96 kB
/** * Get a hash of promises and await them all. * Then return the same hash with the resolved values. * @example * export async function loader({ request }: LoaderArgs) { * return json( * promiseHash({ * user: getUser(request), * posts: getPosts(request), * }) * ); * } * @example * export async function loader({ request }: LoaderArgs) { * return json( * promiseHash({ * user: getUser(request), * posts: promiseHash({ * list: getPosts(request), * comments: promiseHash({ * list: getComments(request), * likes: getLikes(request), * }), * }), * }) * ); * } */ export async function promiseHash(hash) { return Object.fromEntries( await Promise.all( Object.entries(hash).map(async ([key, promise]) => [key, await promise]) ) ); } /** * Used to uniquely identify a timeout * @private */ let TIMEOUT = Symbol("TIMEOUT"); /** * Attach a timeout to any promise, if the timeout resolves first ignore the * original promise and throw an error * @param promise The promise to attach a timeout to * @param options The options to use * @param options.ms The number of milliseconds to wait before timing out * @param options.controller An AbortController to abort the original promise * @returns The result of the promise * @throws TimeoutError If the timeout resolves first * @example * try { * let result = await timeout( * fetch("https://example.com"), * { ms: 100 } * ); * } catch (error) { * if (error instanceof TimeoutError) { * // Handle timeout * } * } * @example * try { * let controller = new AbortController(); * let result = await timeout( * fetch("https://example.com", { signal: controller.signal }), * { ms: 100, controller } * ); * } catch (error) { * if (error instanceof TimeoutError) { * // Handle timeout * } * } */ export function timeout(promise, options) { return new Promise(async (resolve, reject) => { let timer = null; try { let result = await Promise.race([ promise, new Promise((resolve) => { timer = setTimeout(() => resolve(TIMEOUT), options.ms); }), ]); if (timer) clearTimeout(timer); if (result === TIMEOUT) { if (options.controller) options.controller.abort(); return reject(new TimeoutError(`Timed out after ${options.ms}ms`)); } return resolve(result); } catch (error) { if (timer) clearTimeout(timer); reject(error); } }); } /** * An error thrown when a timeout occurs * @example * try { * let result = await timeout(fetch("https://example.com"), { ms: 100 }); * } catch (error) { * if (error instanceof TimeoutError) { * // Handle timeout * } * } */ export class TimeoutError extends Error { constructor(message) { super(message); this.name = "TimeoutError"; } }