Rules Hub

Coding Rules Library

← Back to all rules
fullstack ruleStack: general
asyncerror-handlingnetworkperformanceweb-standards

Merge cancellation signals with AbortSignal.any

Combine multiple cancellation sources (timeouts, user actions) into a single signal using AbortSignal.any to ensure robust resource cleanup.

PR: Feat/FCK-2245 - Cache Bellsheep and profile loaders with TanStack Query #343Created: Dec 10, 2025

Bad example

Old codets
1async function fetchWithTimeout(url: string, parentSignal?: AbortSignal) {
2 const timeoutCtrl = new AbortController();
3 const id = setTimeout(() => timeoutCtrl.abort(), 5000);
4
5 try {
6 // BAD: The fetch only respects the timeout.
7 // If the user navigates away (triggering parentSignal), the request continues running.
8 const res = await fetch(url, { signal: timeoutCtrl.signal });
9 return res.json();
10 } finally {
11 clearTimeout(id);
12 }
13}

Explanation (EN)

By using only the local `timeoutCtrl.signal`, the function ignores the `parentSignal` passed from the caller (e.g., a component unmounting or user navigation). This leads to 'zombie' requests that continue even after they are no longer needed.

Objašnjenje (HR)

Korištenjem samo lokalnog `timeoutCtrl.signal` funkcija ignorira `parentSignal` koji je proslijedio pozivatelj (npr. prilikom demontaže komponente ili navigacije). To dovodi do 'zombie' zahtjeva koji se nastavljaju izvršavati čak i nakon što više nisu potrebni.

Good example

New codets
1import { mergeAbortSignals } from '@/lib/utils'; // Wrapper for AbortSignal.any
2
3async function fetchWithTimeout(url: string, parentSignal?: AbortSignal) {
4 const timeoutCtrl = new AbortController();
5 const id = setTimeout(() => timeoutCtrl.abort(), 5000);
6
7 // GOOD: Combines both signals. The request aborts if EITHER the timeout fires OR parentSignal aborts.
8 // Uses AbortSignal.any() under the hood.
9 const combinedSignal = mergeAbortSignals(parentSignal, timeoutCtrl.signal);
10
11 try {
12 const res = await fetch(url, { signal: combinedSignal });
13 return res.json();
14 } finally {
15 clearTimeout(id);
16 }
17}

Explanation (EN)

All potential cancellation sources are merged into a single `AbortSignal`. Using `AbortSignal.any` (or a robust polyfill) ensures that the operation terminates immediately when the first signal aborts, preventing resource wastage and memory leaks.

Objašnjenje (HR)

Svi potencijalni izvori otkazivanja spojeni su u jedan `AbortSignal`. Korištenje `AbortSignal.any` (ili robusnog polyfilla) osigurava da se operacija odmah prekine čim se prvi signal aktivira, čime se sprječava rasipanje resursa i curenje memorije.

Notes (EN)

Modern browsers and Node.js (v20+) support `AbortSignal.any()` natively. For older environments, use a utility function that gracefully falls back to a manual `AbortController` implementation with proper event cleanup.

Bilješke (HR)

Moderni preglednici i Node.js (v20+) nativno podržavaju `AbortSignal.any()`. Za starija okruženja koristite pomoćnu funkciju koja se elegantno vraća na ručnu implementaciju `AbortController` uz ispravno čišćenje događaja.