Async, Promises i obsługa błędów
Frontend ZEUS nieustannie rozmawia z API. Asynchroniczny kod, który źle obsługuje błędy, daje białe ekrany i ciche awarie. Ta lekcja porządkuje wzorce async/await i obsługę błędów.
async/await zamiast łańcuchów .then
// czytelnie — async/await
async function loadProbes(): Promise<Probe[]> {
const res = await fetch("/api/probes");
if (!res.ok) {
throw new Error(`API ${res.status}`);
}
return res.json();
}
Standard ProfessNet:
fetchnie rzuca wyjątku dla statusów 4xx/5xx. Zawsze sprawdzamyres.oki rzucamy jawny błąd — inaczejres.json()zwróci treść błędu jako „dane".
Równoległość
Niezależne żądania uruchamiamy współbieżnie, nie jedno po drugim.
// wolno — sekwencyjnie
const probes = await loadProbes();
const alerts = await loadAlerts();
// szybko — równolegle
const [probes, alerts] = await Promise.all([loadProbes(), loadAlerts()]);
Gdy część może się nie udać, a reszta ma działać dalej, używamy allSettled:
const results = await Promise.allSettled(forests.map(scanForest));
const ok = results.filter((r) => r.status === "fulfilled");
Obsługa błędów
Każde await z I/O ma swój try/catch lub jest opakowane wyżej.
async function refresh() {
try {
const data = await loadProbes();
setProbes(data);
} catch (err) {
console.error("Nie udało się pobrać probe'ów", err);
toast.error("Błąd pobierania danych");
}
}
Standard ProfessNet: nie połykamy błędów po cichu. Co najmniej log + sygnał dla użytkownika (toast/komunikat). Pusty
catch {}jest zabroniony.
error jest typu unknown
W TypeScript strict błąd w catch ma typ unknown — trzeba go zawęzić.
catch (err) {
const msg = err instanceof Error ? err.message : "Nieznany błąd";
toast.error(msg);
}
Timeout i anulowanie
Żądania mogą wisieć. Używamy AbortController do timeoutu i sprzątania.
async function loadWithTimeout(url: string, ms = 10_000) {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), ms);
try {
const res = await fetch(url, { signal: ctrl.signal });
return await res.json();
} finally {
clearTimeout(t);
}
}
W useEffect AbortController chroni przed aktualizacją odmontowanego komponentu:
useEffect(() => {
const ctrl = new AbortController();
fetch("/api/probes", { signal: ctrl.signal })
.then((r) => r.json())
.then(setProbes)
.catch(() => {});
return () => ctrl.abort();
}, []);
| Wzorzec | Do czego |
|---|---|
await + res.ok | pojedyncze żądanie z kontrolą statusu |
Promise.all | wiele żądań, wszystkie muszą się udać |
Promise.allSettled | wiele żądań, część może paść |
AbortController | timeout i sprzątanie w useEffect |
Wskazówka: w komponentach klienckich rozważ bibliotekę typu TanStack Query — daje cache, retry, stany ładowania i anulowanie out-of-the-box.
Sprawdzaj res.ok, łap błędy, pokazuj je użytkownikowi i anuluj wiszące żądania.
To różnica między aplikacją, która „czasem nie działa", a taką, której się ufa.