This is an overview of the helper functions available in the package. These utilities are designed to simplify working with AbortSignal, debouncing, timeouts, and time conversions.
The functions below are based on the AbortError class. It is used to provide consistent and informative error objects when an operation is aborted.
import { isAbortError, debounce } from 'saborter/lib';A type guard function that determines whether a given error is an AbortError. It uses multiple heuristics to identify abort errors, including checking the error's type, its name property, its message content, and recursively examining the error's cause chain.
Parameters:
error: any- The value to check.
Returns:
error is Error - type guard.
Returns true if the value is identified as an AbortError, otherwise false. When true, TypeScript narrows the type to Error.
Description:
The function performs the following checks in order:
- Instance check: If
erroris an instance ofAbortError, it returnstrue. - Name property check: If
erroris an object and has anameproperty equal to'AbortError', it returnstrue. - Message substring check: If
errorhas amessageproperty that contains the substring'abort', it returnstrue. This matches common error messages like "The operation was aborted". - Cause chain check: It recursively checks the error's
causeproperty (if any). If any error in the cause chain satisfies one of the above conditions, it returnstrue.
If none of these checks pass, it returns false.
This lenient approach ensures that various representations of abort errors (e.g., standard AbortError instances, plain objects, or errors with a nested cause) are correctly identified, making it useful in environments where the exact error class may not be available or where errors are wrapped.
Important
- The method will return
trueeven if it receives a native AbortError that is thrown by theDOMExceptionitself, or finds a hint of a request abort in the error message. - To exclusively verify that the error is an
AbortErrorfrom thesaborterpackage, it is better to use:error instance AbortError
Examples:
const abortError = new AbortError('Aborted');
isAbortError(abortError); // trueconst fakeAbort = { name: 'AbortError', message: 'Cancelled' };
isAbortError(fakeAbort); // trueconst error = new Error('The operation was aborted');
isAbortError(error); // trueconst inner = new AbortError('Inner abort');
const outer = new Error('Wrapper', { cause: inner });
isAbortError(outer); // trueconst regularError = new Error('Something went wrong');
isAbortError(regularError); // false
const nullValue = null;
isAbortError(nullValue); // falseThis function catches errors that are AbortError's and ignores them, while re‑throwing any other error. It is useful in scenarios where you want to handle abort errors silently (e.g., because they are expected and you don't need to act on them) but still propagate genuine errors.
Parameters:
error: any- The error object to inspect.options?: Object- Configuration options.strict?: boolean(Defaultfalse) - Iftrue, the function useserror instanceof AbortErrorto identify an abort error. Iffalse, it uses the more lenientisAbortErrorcheck (which may also recognize custom abort errors).
Returns:
void | never
voidif the error is anAbortError(the function does nothing, effectively silencing it).never– throws the original error if it is not anAbortError.
Example:
try {
await fetchWithTimeout(url, { signal });
} catch (error) {
catchAbortError(error); // Non‑abort errors are re‑thrown; abort errors are ignored.
// If execution reaches this point, it means the error was an AbortError and we can ignore it.
}Creates a debounced function that delays invoking the provided handler until after a specified timeout has elapsed since the last call. This is a leading‑edge debounce – the first call in a burst schedules the execution, and subsequent calls reset the timer. The debounced function accepts an AbortSignal and returns a promise that resolves with the handler's result or rejects if the handler throws or the signal is aborted.
Parameters:
handler: <R>(signal: AbortSignal) => R | Promise<R>- A function that takes anAbortSignaland returns a value or aPromise. This is the function to debounce.delay?: number- The debounce delay in milliseconds. If not provided, the handler may be invoked immediately (depending on the underlyingsetTimeoutAsync).
Returns:
(signal: AbortSignal) => R | Promise<R>
A function that accepts an AbortSignal and returns a Promise<R>, where R is the return type of the handler.
Error handling:
- If the underlying
setTimeoutAsyncthrows anAbortError, the error is enriched with a cause (a newAbortErrorcontaining the original error) and itsinitiatorproperty is set to'debounce'before being re‑thrown. - Any other error is re‑thrown unchanged.
Examples:
const debouncedFetch = debounce((signal) => fetch('/api/search', { signal }), 300);
const controller = new AbortController();
debouncedFetch(controller.signal)
.then((response) => response.json())
.catch((err) => {
if (err instanceof AbortError) {
console.log('Debounced call aborted by:', err.initiator); // 'debounce'
}
});const data = await aborter.try(debounce((signal) => fetch('/api/data', { signal }), 300));A type guard that checks whether a given value is an instance of AbortSignal.
Parameters:
value: any- The value to test.
Returns:
boolean – true if the value is an AbortSignal, false otherwise.
Example:
const controller = new AbortController();
console.log(isAbortSignal(controller.signal)); // true
console.log(isAbortSignal({})); // falseThis function is the complement of catchAbortError. It re‑throws the error only if it is an AbortError; otherwise, it does nothing. This is useful in error‑handling patterns where you want to let abort errors propagate (so they can be caught elsewhere) while handling other errors locally.
Parameters:
error: any- The error to inspect.options?: Object:strict?: boolean(defaultfalse) - Iftrue, useserror instanceof AbortError. Iffalse, uses the more lenientisAbortErrorcheck.
Returns:
void | never
voidif the error is not anAbortError.never– throws the original error if it is anAbortError.
Example:
try {
await someOperation(signal);
} catch (error) {
rethrowAbortError(error); // Only re‑throws if it's an abort error.
// Handle other errors here.
}Schedules the execution of a handler after a specified delay. The operation can be cancelled using an AbortSignal. This function returns a promise that resolves with the handler's result or rejects if the timeout is aborted or if the handler throws an error.
Parameters:
handler: ((signal: AbortSignal) => T | Promise<T>):- A function that accepts an
AbortSignaland returns a value or aPromise. This function will be called with the signal to allow cleanup on abort.
- A function that accepts an
delay?: number- The time in milliseconds to wait before executing the handler. If omitted, the handler is scheduled without a delay (i.e., as soon as possible).options?: Object:signal?: AbortSignal- AnAbortSignalthat can be used to cancel the timeout. If not provided, a newAbortControlleris created internally.args?: any[]- Arguments to pass to the handler.
Returns:
Promise<T> – resolves with the handler's result, or rejects with an AbortError if the operation was aborted, or with any error thrown by the handler.
Behavior:
- If the provided signal is already aborted when
setTimeoutAsyncis called, it immediately rejects with anAbortError. - When the
handleris a function, it is called with the signal. If the function returns a promise, the promise is chained; otherwise, the return value is used directly. - If the
signalisabortedafter the timeout has been set, the timeout is cleared and the promise rejects with anAbortError. The error includes the original signal reason and the initiator is set to'setTimeoutAsync'.
Examples:
const controller = new AbortController();
setTimeoutAsync(
(signal) => {
return fetch('/api/data', { signal }).then((res) => res.json());
},
5000,
{
signal: controller.signal
}
)
.then((data) => console.log(data))
.catch((error) => console.log(error.name)); // 'AbortError' if abortedconst controller = new AbortController();
try {
const data = await setTimeoutAsync(
async (signal) => {
const response = await fetch('/api/data', { signal });
return await response.json();
},
5000,
{ signal: controller.signal }
);
} catch (error) {
console.log(error.name); // 'AbortError' if aborted
}const delay = (ms: number) => setTimeoutAsync(() => null, ms);
console.log('Hello');
await delay(2000);
console.log('World');The setTimeoutAsync function can be used like a regular native setTimeout function, but instead of returning an ID for deletion from the EventLoop, it returns the values you returned from the callback:
// Getting a token from local storage in 5 seconds
const token = await setTimeoutAsync(() => localStorage.getItem('token'), 5000); // string | nullconst controller = new AbortController();
// Or you can use an ReusableAborter
try {
const token = await setTimeoutAsync(
() => {
return localStorage.getItem('token');
},
5000,
{ signal: controller.signal }
);
} catch (error) {
if (isAbortError(error)) {
console.log(error.name); // 'AbortError'
}
}A utility that checks whether an AbortSignal has been aborted. If the signal is aborted, it throws an AbortError. This is useful for manual abortion checks inside long‑running operations that do not automatically handle the signal.
Parameters:
signal: AbortSignal- The signal to check.
Returns:
void | never
voidif the signal is not aborted.never– throws anAbortErrorif the signal is aborted.
Behavior:
- If the signal's
reasonis already an instance ofAbortError, that exact error is thrown (preserving its cause and initiator). - Otherwise, a new AbortError is created with a default message and the original reason attached. The initiator is set to
'throwIfAborted'.
Example:
const processItems = (items: unknown[], signal: AbortSignal) => {
try {
for (const item of items) {
throwIfAborted(signal); // Check before each iteration
// Process item...
}
} catch (error) {
// Handle error
}
};Combines multiple abort signals into a single signal that aborts when any of the input signals aborts. This is useful when you need to cancel an operation if any of several independent signals (e.g., from different sources) become aborted.
Signature:
export const abortSignalAny = <T extends AbortSignalLike | AbortSignalLike[]>(...args: T[]): AbortSignalWhere AbortSignalLike = AbortSignal | null | undefined.
Parameters:
...args– A rest parameter that accepts any number of arguments. Each argument can be:- A single
AbortSignal(ornull/undefined– these are ignored). - An array of
AbortSignalLike.
- A single
This function accepts either an unlimited number of signals or an array of signals.
Returns:
A new AbortController.signal that will be aborted when any of the input signals aborts. If any input signal is already aborted when the function is called, the returned signal is immediately aborted.
Description:
The function works as follows:
- Flattens the provided arguments into a single array of signals (ignoring
nullorundefined). - Creates a new
AbortController. - For each signal in the flattened list:
- If the signal is already aborted, the controller is aborted immediately with a custom
AbortError(see error handling below) and no further listeners are attached. - Otherwise, it attaches a one‑time
'abort'event listener to that signal. When the signal aborts, the handler is called, which:- Aborts the controller using the same
AbortErrorcreated from the aborting signal. - Cleans up all listeners from all other signals (removes the
'abort'event handlers) to prevent memory leaks.
- Aborts the controller using the same
The function ensures that the controller is aborted only once, even if multiple signals abort simultaneously or in quick succession.
Error Handling:
The function creates a consistent AbortError object when aborting the controller. It uses the helper createAbortError, which:
- If the signal’s
reasonis already anAbortError, that error is reused. - If the signal’s
reasonis aDOMExceptionwith the name'AbortError'(as in browser‑native abort), it stores the original reason under acauseproperty. - Otherwise, it creates a new
AbortErrorwith the message'The operation was aborted'and attaches the original reason under areasonproperty.
In all cases, the resulting error has an initiator property set to 'abortSignalAny' to help trace the source of the abort.
Examples:
import { abortSignalAny } from '.saborter/lib';
const ac1 = new AbortController();
const ac2 = new AbortController();
const combined = abortSignalAny(ac1.signal, ac2.signal);
combined.addEventListener('abort', () => console.log('Combined signal aborted!'));
ac1.abort(); // triggers combined abortconst signals = [ac1.signal, ac2.signal];
const combined = abortSignalAny(signals);const ac = new AbortController();
ac.abort(); // signal is already aborted
const combined = abortSignalAny(ac.signal); // returns an already aborted signal
combined.aborted; // trueconst combined = abortSignalAny(null, undefined, ac.signal); // only ac.signal is consideredConverts a configuration object containing time components (hours, minutes, seconds, milliseconds) into a total number of milliseconds. All components are optional and default to 0 if not provided.
Parameters:
timeMsConfig: Object- An object with the following optional numeric properties:hours?: number- hours to add.minutes?: number- minutes to add.seconds?: number- seconds to add.milliseconds?: number- milliseconds to add.
Returns:
number - the total time in milliseconds.
Throws:
TypeError– if any of the provided values is not a number orundefined.
Example:
timeInMilliseconds({ seconds: 1 }); // Returns 1000
timeInMilliseconds({ minutes: 1, seconds: 30 }); // Returns 90000
timeInMilliseconds({ hours: 1, minutes: 30, seconds: 45, milliseconds: 500 }); // Returns 5,445,500A function that allows you to clear an object's data, if the object supports this feature.
Parameters:
object: any- an object that supports resource cleaning.
Returns:
void - The function does not return anything.
Throws:
ReferenceError– if the object does not support resource cleanup.