UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

80 lines (79 loc) 2.56 kB
import { _isTruthy } from './is.util.js'; /** * Creates AbortableSignal, * which is like AbortSignal, but can "abort itself" with `.abort()` method. * * @experimental */ export function createAbortableSignal() { const ac = new AbortController(); return Object.assign(ac.signal, { abort: ac.abort.bind(ac), }); } /** * Returns AbortSignal if ms is defined. * Otherwise returns undefined. */ export function abortSignalTimeoutOrUndefined(ms) { return ms ? abortSignalTimeout(ms) : undefined; } /** * Returns an AbortSignal that aborts after the given number of milliseconds. * Uses native `AbortSignal.timeout()` when available, falls back to a polyfill. * * The abort reason is a DOMException with name "TimeoutError". */ export function abortSignalTimeout(ms) { return typeof AbortSignal.timeout === 'function' ? AbortSignal.timeout(ms) : polyfilledAbortSignalTimeout(ms); } export function polyfilledAbortSignalTimeout(ms) { const ac = new AbortController(); setTimeout(() => { ac.abort(new DOMException('The operation was aborted due to timeout', 'TimeoutError')); }, ms); return ac.signal; } /** * Returns AbortSignal.any(signals) is the array (after filtering undefined inputs) is not empty, * otherwise undefined. */ export function abortSignalAnyOrUndefined(signals) { const filtered = signals.filter(_isTruthy); return filtered.length ? abortSignalAny(filtered) : undefined; } /** * Returns an AbortSignal that aborts when any of the given signals abort. * Uses native `AbortSignal.any()` when available, falls back to a polyfill. * * The abort reason is taken from the first signal that aborts. * If any input signal is already aborted, the returned signal is immediately aborted. * * If only 1 signal is passed in the input array - that Signal is returned as-is. */ export function abortSignalAny(signals) { if (signals.length === 1) { return signals[0]; } return typeof AbortSignal.any === 'function' ? AbortSignal.any(signals) : polyfilledAbortSignalAny(signals); } export function polyfilledAbortSignalAny(signals) { const ac = new AbortController(); for (const signal of signals) { if (signal.aborted) { ac.abort(signal.reason); return ac.signal; } } for (const signal of signals) { signal.addEventListener('abort', () => ac.abort(signal.reason), { once: true, signal: ac.signal, }); } return ac.signal; }