AbortController / AbortSignal.timeout în JavaScript

Cereri HTTP și comunicare Browserele moderne, Node.js 16+ (AbortSignal.any: Node.js 20+)

Oprește o cerere fetch sau altă operație asincronă: la comandă, după un timp sau la primul dintre mai multe semnale.

Sintaxă
const controller = new AbortController();
fetch(url, { signal: controller.signal });
controller.abort();
fetch(url, { signal: AbortSignal.timeout(5000) })

Ce face AbortController / AbortSignal.timeout

Un AbortController are un signal, pe care îl dai operației (lui fetch, unui addEventListener sau propriilor funcții). Când apelezi abort(motiv), operația se oprește și promisiunea ei este respinsă cu o eroare AbortError (sau cu motivul dat).

Metode statice utile: AbortSignal.timeout(ms) creează un semnal care se declanșează singur după un timp (eroare TimeoutError), AbortSignal.any([s1, s2]) se declanșează la primul dintre semnale, iar AbortSignal.abort() creează un semnal deja declanșat. În funcțiile tale, signal.throwIfAborted() aruncă eroarea dacă semnalul a fost declanșat.

Parametri

Parametru Descriere
motiv Opțional, pentru abort: motivul opririi (implicit o eroare AbortError).

Ce returnează

Un controller cu proprietatea signal.

Exemple

Exemplul 1: Oprire la comandă într-o funcție proprie

function numara(signal) {
  return new Promise((resolve, reject) => {
    let n = 0;
    const id = setInterval(() => console.log(++n), 50);
    signal.addEventListener("abort", () => {
      clearInterval(id);
      reject(signal.reason);
    });
  });
}

const controller = new AbortController();
setTimeout(() => controller.abort(), 175);
try {
  await numara(controller.signal);
} catch (e) {
  console.log(e.name);
}

Rezultat

1
2
3
AbortError

Exemplul 2: Limită de timp și semnale combinate

const pauza = (ms, signal) => new Promise((resolve, reject) => {
  const id = setTimeout(resolve, ms);
  signal.addEventListener("abort", () => { clearTimeout(id); reject(signal.reason); });
});

try {
  await pauza(1000, AbortSignal.timeout(100));
} catch (e) {
  console.log(e.name);
}

const utilizator = new AbortController();
const semnal = AbortSignal.any([utilizator.signal, AbortSignal.timeout(5000)]);
utilizator.abort(new Error("Anulat de utilizator"));
console.log(semnal.aborted, semnal.reason.message);

try {
  AbortSignal.abort().throwIfAborted();
} catch (e) {
  console.log(e.name);
}

Rezultat

TimeoutError
true Anulat de utilizator
AbortError

Exemplul 3: fetch cu limită de 5 secunde

try {
  const raspuns = await fetch("https://api.lenta.exemplu.ro/raport", { signal: AbortSignal.timeout(5000) });
  console.log(await raspuns.json());
} catch (e) {
  if (e.name === "TimeoutError") console.log("Serverul nu a răspuns în 5 secunde");
  else throw e;
}

Rezultat posibil (depinde de răspunsul serverului)

Serverul nu a răspuns în 5 secunde

Greșeli frecvente

  • Refolosești un controller după abort(). Semnalul rămâne declanșat pentru totdeauna; creează un controller nou pentru fiecare cerere.
  • Tratezi oprirea ca pe o eroare reală și afișezi un mesaj de eroare utilizatorului. Verifică e.name === "AbortError" și ignoră cazul.

Comenzi înrudite

  • fetch: Trimite o cerere HTTP la un server și primește răspunsul, fără reîncărcarea paginii.
  • Promise.race: Returnează rezultatul (sau eroarea) primei promisiuni care se termină.
  • addEventListener: Rulează o funcție când se întâmplă ceva pe pagină: un clic, o tastă, trimiterea unui formular.