export class TimeoutError extends Error { constructor(message) { super(message); this.name = 'TimeoutError'; } } /** An error to be thrown when the request is aborted by AbortController. DOMException is thrown instead of this Error when DOMException is available. */ export class AbortError extends Error { constructor(message) { super(); this.name = 'AbortError'; this.message = message; } } /** TODO: Remove AbortError and just throw DOMException when targeting Node 18. */ const getDOMException = errorMessage => globalThis.DOMException === undefined ? new AbortError(errorMessage) : new DOMException(errorMessage); /** TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18. */ const getAbortedReason = signal => { const reason = signal.reason === undefined ? getDOMException('This operation was aborted.') : signal.reason; return reason instanceof Error ? reason : getDOMException(reason); }; export default function pTimeout(promise, options) { const { milliseconds, fallback, message, customTimers = {setTimeout, clearTimeout}, } = options; let timer; const cancelablePromise = new Promise((resolve, reject) => { if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) { throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``); } if (milliseconds === Number.POSITIVE_INFINITY) { resolve(promise); return; } if (options.signal) { const {signal} = options; if (signal.aborted) { reject(getAbortedReason(signal)); } signal.addEventListener('abort', () => { reject(getAbortedReason(signal)); }); } timer = customTimers.setTimeout.call(undefined, () => { if (fallback) { try { resolve(fallback()); } catch (error) { reject(error); } return; } const errorMessage = typeof message === 'string' ? message : `Promise timed out after ${milliseconds} milliseconds`; const timeoutError = message instanceof Error ? message : new TimeoutError(errorMessage); if (typeof promise.cancel === 'function') { promise.cancel(); } reject(timeoutError); }, milliseconds); (async () => { try { resolve(await promise); } catch (error) { reject(error); } finally { customTimers.clearTimeout.call(undefined, timer); } })(); }); cancelablePromise.clear = () => { customTimers.clearTimeout.call(undefined, timer); timer = undefined; }; return cancelablePromise; }