07.09 Try/Catch s async
Výuka
Proč Try/Catch s async?
V předchozí lekci jsme se naučili async/await - čisté a čitelné vyjádření asynchronního kódu. Ale co se stane, když něco selže? Když Promise skončí rejection místo fulfillment?
Při klasických Promises jsme používali .catch():
fetchData()
.then(data => zpracujData(data))
.catch(error => console.error(error));
S async/await ale nemáme .catch() k dispozici - píšeme kód, který vypadá synchronně. Naštěstí JavaScript má pro synchronní kód osvědčený mechanismus zachycení chyb: try/catch.
Představ si to jako: Záchranná síť pod provazochodcem. Když akrobat (tvůj kód) balancuje na laně (asynchronní operace), síť (try/catch) ho zachytí, pokud spadne (nastane chyba). Bez sítě by spadl až na zem (unhandled rejection → crash/varování).
Jak to funguje?
1. Obalíš "nebezpečný" await kód do bloku try { }
2. Pod něj přidáš catch(error) { } pro zachycení chyb
3. Když await vrátí rejected Promise → program skočí do catch
4. Volitelně finally { } pro kód, který se provede VŽDY
Klíčový princip: Když await čeká na Promise, který skončí rejection, JavaScript "hodí" (throw) tuto chybu - jako kdyby tam byl synchronní throw. Blok try/catch ji zachytí.
Rozdíl oproti .catch()
| Aspekt | .catch() |
try/catch |
|---|---|---|
| Styl kódu | Funkcionální (řetězení) | Imperativní (blokový) |
| Čitelnost | Méně podobné běžnému kódu | Vypadá jako běžný synchronní kód |
| Scope | Zachytí chyby v řetězci | Zachytí chyby v bloku try |
| Použití | S .then() |
S async/await |
Klíčové koncepty
- try - "Zkus provést tento kód, ale může selhat"
- catch - "Když kód selže, tady zachytím chybu"
- finally - "Tento kód proveď VŽDY, ať už úspěch nebo chyba"
- throw - "Vyhazuji chybu (rejection se převede na throw)"
Anatomie error objektu
Když catchneš error z Promise rejection, dostaneš buď:
- Error objekt s
.messagea.stack - Libovolnou hodnotu (pokud někdo udělal
reject("text"))
Proto je dobré vždy kontrolovat, s čím pracuješ!
JavaScript
// Základní try/catch s async/await
async function nactiUzivatele(id) {
try {
// Nebezpečná operace - může selhat
const response = await fetch(`/api/users/${id}`);
// I úspěšný fetch může vrátit chybový status
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const user = await response.json();
return user;
} catch (error) {
// Všechny chyby skončí tady
console.error("Nepodařilo se načíst uživatele:", error.message);
// Můžeme vrátit výchozí hodnotu
return null;
} finally {
// Provede se VŽDY (i po return!)
console.log("Operace dokončena");
}
}
// Použití
async function main() {
const user = await nactiUzivatele(123);
if (user) {
console.log("Uživatel:", user.name);
} else {
console.log("Uživatel nenalezen");
}
}
main();
Co se stane?
fetch()může selhat (síťová chyba, timeout, CORS...)- Pokud selže → await "hodí" chybu → skočíme do catch
response.json()může selhat (nevalidní JSON)- Pokud cokoliv selže → error obsahuje informace
finallyse provede VŽDY - ideální pro úklid
Zachycení více typů chyb
async function zpracujData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
// Tady může být další logika
return data;
} catch (error) {
// Rozlišení typu chyby
if (error instanceof TypeError) {
// Síťová chyba (fetch selhal úplně)
console.error("Problém se sítí:", error.message);
} else if (error instanceof SyntaxError) {
// JSON parsing selhal
console.error("Server vrátil nevalidní data");
} else {
// Jiný typ chyby
console.error("Neočekávaná chyba:", error);
}
// Re-throw pokud nechceme chybu "spolknout"
throw error;
}
}
Nebezpečí: Paralelní await bez správného catchování
// ❌ PROBLÉM: Druhý await neproběhne, pokud první selže
async function spatne() {
try {
const user = await fetchUser(); // Pokud selže...
const posts = await fetchPosts(); // ...toto se vůbec nespustí
return { user, posts };
} catch (error) {
// Nezachytíme chybu z fetchPosts, pokud fetchUser uspěl
// ale fetchPosts selhal až "mezitím"
}
}
// ✅ SPRÁVNĚ: Promise.all pro paralelní operace
async function lepe() {
try {
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
return { user, posts };
} catch (error) {
// Zachytí chybu z KTERÉHOKOLIV Promise
console.error("Něco selhalo:", error);
}
}
TypeScript
// TypeScript: Typované chyby a výsledky
// Definice vlastní chybové třídy
class ApiError extends Error {
constructor(
message: string,
public statusCode: number,
public endpoint: string
) {
super(message);
this.name = "ApiError";
}
}
// Typovaný interface pro odpověď
interface User {
id: number;
name: string;
email: string;
}
// Funkce s jasně definovanými typy
async function nactiUzivatele(id: number): Promise<User | null> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new ApiError(
`Failed to fetch user`,
response.status,
`/api/users/${id}`
);
}
const user: User = await response.json();
return user;
} catch (error: unknown) {
// TypeScript 4.4+: error je typu 'unknown'
// Musíme ho správně zkontrolovat
if (error instanceof ApiError) {
console.error(
`API chyba (${error.statusCode}): ${error.message}`
);
} else if (error instanceof Error) {
console.error(`Obecná chyba: ${error.message}`);
} else {
console.error(`Neznámá chyba:`, error);
}
return null;
}
}
// Alternativa: Result pattern (žádné výjimky)
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function nactiUzivateleSafe(id: number): Promise<Result<User, ApiError>> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
return {
success: false,
error: new ApiError("Fetch failed", response.status, `/api/users/${id}`)
};
}
const user: User = await response.json();
return { success: true, data: user };
} catch (error) {
return {
success: false,
error: new ApiError(
error instanceof Error ? error.message : "Unknown error",
0,
`/api/users/${id}`
)
};
}
}
// Použití Result pattern
async function main(): Promise<void> {
const result = await nactiUzivateleSafe(123);
if (result.success) {
console.log("Uživatel:", result.data.name);
} else {
console.error("Chyba:", result.error.message);
}
}
TypeScript přidává:
- ✅
error: unknownv catch bloku - nuceni jsme zkontrolovat typ - ✅ Vlastní error třídy s typed properties (
statusCode,endpoint) - ✅
Resultpattern - explicitní práce s úspěchem/chybou bez výjimek - ✅ Typovaná návratová hodnota
Promise
Rozdíl JS vs TS
JavaScript:
catch(error)- error je implicitněany- Můžeš s ním dělat cokoliv (včetně přístupu k neexistujícím vlastnostem)
- Žádná kontrola typu při kompilaci
TypeScript:
catch(error: unknown)- musíš zkontrolovat typ před použitím- Vlastní error třídy s typovanými vlastnostmi
- IDE ti napovídá dostupné vlastnosti po type narrowing
// TypeScript rozdíl v praxi
// ❌ JS přístup - nebezpečné
catch (error) {
console.log(error.response.data.message);
// Pokud error nemá response → runtime crash!
}
// ✅ TS přístup - bezpečné
catch (error: unknown) {
if (
error instanceof Error &&
"response" in error &&
typeof (error as any).response?.data?.message === "string"
) {
console.log((error as any).response.data.message);
} else {
console.log("Neznámá chyba");
}
}
Tip
💡 Nepolykat chyby bezdůvodně:
// ❌ Špatně - chyba zmizí, nikdo se nedozví
async function spatne() {
try {
await nebezpecnaOperace();
} catch (error) {
// Prázdný catch = spolknutá chyba!
}
}
// ✅ Správně - alespoň zalogovat, nebo předat dál
async function lepe() {
try {
await nebezpecnaOperace();
} catch (error) {
console.error("Operace selhala:", error);
throw error; // Předáme dál, pokud je to vhodné
}
}
💡 Finally pro úklid zdrojů:
async function pracujSSouborem() {
let file = null;
try {
file = await otevriSoubor("data.txt");
const obsah = await file.read();
return zpracuj(obsah);
} catch (error) {
console.error("Chyba při práci se souborem:", error);
return null;
} finally {
// Zavři soubor VŽDY - i při úspěchu, i při chybě
if (file) {
await file.close();
}
}
}
💡 Globální handler pro nezachycené Promise rejection:
// V prohlížeči
window.addEventListener("unhandledrejection", (event) => {
console.error("Nezachycená Promise rejection:", event.reason);
// Logování do analytiky, zobrazení uživateli, atd.
});
// V Node.js
process.on("unhandledRejection", (reason, promise) => {
console.error("Nezachycená Promise rejection:", reason);
});
Kvíz
Co se stane, když await čeká na Promise, který skončí rejection?
❌ - Nezachycená rejection nezpůsobí návrat undefined, způsobí výjimku
✅ - Přesně tak! await na rejected Promise způsobí "throw", který lze zachytit try/catch blokem
❌ - Chyba JDE zachytit pomocí try/catch (nebo globálního handleru)
❌ - V prohlížeči se zobrazí varování, ale kód nepokračuje normálně. V novějších verzích Node.js může nezachycená rejection i ukončit proces
🎯 Závěrečný projekt
Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.
Zobrazit podrobnosti projektu →Informace o seriálu
Obtížnost
Délka
Cca 480 minut
Počet videí
8 videí + projekty
Certifikát
Po dokončení obdržíte certifikát
Lekce v této sekci
- 7.1 Synchronní vs asynchronní programování
- 7.2 Callbacks
- 07.03 Callback Hell
- 07.04 Promises úvod
- 07.05 Then a Catch
- 07.06 Promise.all
- 07.07 Promise.race
- 07.08 Async/Await
- 07.09 Try/Catch s async
- 07.10 Fetch API
- 7.11 Generátory
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě