Přeskočit na obsah
Kurz Reactu1.0.0 beta
CSEN
Kurz Reactu1.0.0 beta
CSEN
🏠 Úvod🧭 Kde začít?🔁 Opakování📄 Taháky📰 Co je novéhoℹ️ O kurzu
JavaScript0/22

JavaScript obecně

  • 01 Proměnné, typy a operátory0/2
  • 02 Funkce a closures0/2
  • 03 Objekty0/2
  • 04 Pole I: map, filter a spol.0/2
  • 05 Pole II: reduce, řazení a seskupování0/3
  • 06 Podmínky a logické operátory0/2
  • 07 Asynchronní JavaScript0/2
  • 08 Moduly a vestavěné nástroje0/2

JavaScript pro React

  • 09 Reference a immutabilita0/3
  • 10 JS vzory, které v Reactu potkáš všude0/2
TypeScript0/6

Základy

  • 01 Rychlé opakování základů0/3
  • 02 Stav a události (useState)0/3

Hooky do hloubky

  • 03 Efekty (useEffect)0/3
  • 04 Refy (useRef)0/3
  • 05 Složitější stav (useReducer)0/3
  • 06 Context0/3
  • 07 Vlastní hooky0/3

Formuláře

  • 08 Formuláře a React 19 Actions0/3

Výkon

  • 09 Výkon a renderování0/3

Vzory

  • 10 Návrhové vzory komponent0/3

Ekosystém

  • 11 TypeScript s Reactem0/3
  • 12 Routování (React Router)0/3
  • 13 Načítání dat0/3
  • 14 Správa stavu aplikace0/3

Projekt

  • 15 Závěrečný projekt: Kanban0/2

Shrnutí

  • 16 Shrnutí: principy Reactu

Tvůj účet

Ochrana osobních údajů

JavaScript 07 · JavaScript obecně

Asynchronní JavaScript

setTimeout a event loop, Promise, async/await, chyby, Promise.all a fetch.

Načítám lekci…

💬 Našel jsi chybu, něco ti není jasné, nebo máš nápad? Napiš mi.
← Podmínky a logické operátoryModuly a vestavěné nástroje →

Než začneme: číšník s lístečky

Představ si restauraci s jediným číšníkem. Kdyby po každé objednávce stál u kuchyně a čekal, až kuchař dovaří, ostatní hosté by se ani nedostali k objednání. Proto to dělá chytře: objednávku odnese do kuchyně, hostovi nechá lísteček („jídlo bude“) a jde obsloužit další stůl. Když kuchař zazvoní, jídlo donese.

JavaScript v prohlížeči je takový číšník – má jen jedno vlákno. Kdyby čekal na odpověď serveru (která trvá klidně sekundu), celá stránka by zamrzla: nešlo by klikat, psát ani scrollovat. Proto se na pomalé věci nečeká, ale objednávají – a lísteček s budoucím výsledkem se jmenuje Promise.

ℹ️ Co tě v lekci čeká
  1. setTimeout a setInterval.
  2. Event loop: proč se kód neprovádí vždycky shora dolů.
  3. Promise: lísteček na budoucí výsledek.
  4. async a await: asynchronní kód, který se čte jako normální.
  5. Chyby: try, catch a finally.
  6. Postupně, nebo najednou: Promise.all a spol.
  7. fetch: jak se doopravdy mluví se serverem.
  8. Nejčastější chyby.

1. setTimeout a setInterval

console.log('A')
setTimeout(() => console.log('B – po 1 sekundě'), 1000)
console.log('C')
// Vypíše: A, C, … a za sekundu B
// setTimeout nečeká! Jen „objedná“ zavolání funkce a kód běží dál.
const id = setTimeout(() => alert('Bum'), 5000)
clearTimeout(id) // zruší naplánované zavolání
const tick = setInterval(() => console.log('tik'), 1000) // každou sekundu
clearInterval(tick) // zastaví
⚠️ Po sobě uklízej
Interval běží, dokud ho nezastavíš – i když už ho nikdo nepotřebuje. V Reactu se proto intervaly a timeouty ruší v úklidové funkci efektu (lekce React 03). Bez toho by se po každém zobrazení komponenty přidal další interval.

2. Event loop: v jakém pořadí se kód provede

Číšník má pravidla: nejdřív dodělá, co právě dělá (synchronní kód). Pak se podívá na naléhavé lístečky (mikroúlohy – splněné Promise). Teprve potom vezme další běžnou úlohu z fronty (setTimeout, kliknutí, odpověď serveru).

console.log('1')
setTimeout(() => console.log('4'), 0) // i s nulou až po všem ostatním
Promise.resolve().then(() => console.log('3')) // mikroúloha – před timeoutem
console.log('2')
// 1, 2, 3, 4
Ukázka

Pořadí výpisů

Co vidíš: Kód s console.log, setTimeout a Promise. Tlačítko ho spustí a ukáže, v jakém pořadí se výpisy objevily.

Vyzkoušej:

  1. Než klikneš, zkus si tipnout pořadí.
  2. Klikni na Spustit. Synchronní výpisy jsou první, pak mikroúlohy (Promise, queueMicrotask), a setTimeout s nulou až úplně nakonec.

Co z toho plyne: setTimeout(fn, 0) neznamená „hned“, ale „až bude volno“. Synchronní kód vždy doběhne celý, než se na řadu dostane cokoli asynchronního.

Načítám interaktivní část…

❓ Co když synchronní kód trvá dlouho?

Pak čeká všechno ostatní – i kliknutí a vykreslování. Smyčka přes milion položek nebo složitý výpočet tak stránku na chvíli „zamrazí“. Proto se pomalé věci (síť, soubory, časovače) dělají asynchronně a s těžkými výpočty pomáhají nástroje z lekce o výkonu.

3. Promise: lísteček na budoucí výsledek

Promise je objekt, který zastupuje hodnotu, jež zatím není k dispozici. Může být ve třech stavech:

StavZnamenáLísteček v restauraci
pendingčeká sejídlo se vaří
fulfilledsplněno – máme hodnotujídlo je na stole
rejectedzamítnuto – nastala chybadošly suroviny
const promise = fetchUser(1) // vrátí Promise hned, data ještě nejsou
console.log(promise) // Promise { <pending> }
// .then – „až to bude, udělej tohle“
promise.then((user) => console.log(user.name))
// .catch – „když se to pokazí“, .finally – „v každém případě“
fetchUser(99)
.then((user) => console.log(user.name))
.catch((error) => console.error('Nepovedlo se:', error.message))
.finally(() => console.log('Hotovo (úspěch i chyba)'))

Řetězení then

fetchUser(1)
.then((user) => fetchPosts(user.id)) // vrátí další Promise…
.then((posts) => posts.items.length) // …a další then dostane jeho výsledek
.then((count) => console.log(count))
.catch((error) => console.error(error)) // jeden catch pro chyby z celého řetězu

Vlastní Promise

Většinou Promise jen dostáváš (z fetch, z knihoven). Občas se ale hodí vyrobit vlastní – typicky čekání:

function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms) // za ms zavolá resolve → Promise se splní
})
}
sleep(1000).then(() => console.log('Uplynula sekunda'))
// Promise, který může selhat
function rollDice() {
return new Promise((resolve, reject) => {
const n = Math.ceil(Math.random() * 6)
if (n === 1) reject(new Error('Padla jednička'))
else resolve(n)
})
}

4. async a await

Řetězy .then fungují, ale čtou se ztěžka. async/await dělá totéž a čte se jako obyčejný kód shora dolů:

// S then
function showUserPosts(id) {
return fetchUser(id)
.then((user) => fetchPosts(user.id))
.then((posts) => console.log(posts.items))
}
// S async/await – totéž
async function showUserPosts(id) {
const user = await fetchUser(id) // počkej na uživatele
const posts = await fetchPosts(user.id) // pak na příspěvky
console.log(posts.items)
}
  • await „rozbalí“ Promise: počká, až se splní, a vrátí jeho hodnotu. Čeká jen tahle funkce – zbytek stránky běží dál.
  • await jde použít jen uvnitř funkce označené async (nebo na nejvyšší úrovni modulu).
  • async funkce vždy vrací Promise. I když napíšeš return 5, volající dostane Promise s pětkou.
async function getNumber() {
return 5
}
getNumber() // Promise { 5 } – ne 5!
const n = await getNumber() // 5
getNumber().then((n) => …) // nebo takhle
// Šipková async funkce
const loadUser = async (id) => {
const user = await fetchUser(id)
return user.name
}

5. Chyby: try, catch, finally

async function loadProfile(id) {
try {
const user = await fetchUser(id) // když tohle selže…
return user
} catch (error) {
console.error(error.message) // …skočí se sem
return null
} finally {
console.log('Načítání skončilo') // proběhne vždycky (úspěch i chyba)
}
}
✨ Typický vzor: loading, data, chyba
let isLoading = true
let error = null
let data = null
try {
data = await fetchUser(id)
} catch (e) {
error = e.message
} finally {
isLoading = false
}
Přesně tyhle tři stavy (načítám / mám data / chyba) budeš v Reactu zobrazovat pořád. V lekci o načítání dat uvidíš, jak to za tebe vyřeší knihovna.
❓ Co se stane s chybou, kterou nikdo nechytí?

V konzoli se objeví „Uncaught (in promise) Error…“ a funkce, která na výsledek čekala, se nedokončí. Na stránce nic neuvidíš – uživatel jen čeká na data, která nepřijdou. Každé volání serveru proto potřebuje plán B.

6. Postupně, nebo najednou?

Když potřebuješ víc nezávislých věcí, je zbytečné čekat na každou zvlášť. Číšník také neodnáší do kuchyně objednávky jednu po druhé a nečeká, až se každá dovaří.

// ❌ Postupně: 4 × ~1 s = ~4 s
const users = []
for (const id of [1, 2, 3, 4]) {
users.push(await fetchUser(id))
}
// ✅ Najednou: ~1 s (tak dlouho, jak trvá nejpomalejší)
const users = await Promise.all([1, 2, 3, 4].map((id) => fetchUser(id)))
// ↑ map spustí všechna 4 načítání hned, all počká na všechna
const [user, posts] = await Promise.all([fetchUser(1), fetchPosts(1)]) // různé věci najednou
Ukázka

Postupně vs. paralelně

Co vidíš: Dvě tlačítka, která načtou čtyři uživatele z falešného API (každý odpovídá za 0,3–1,5 s). Pruhy ukazují, kdy které načítání začalo a skončilo.

Vyzkoušej:

  1. Klikni na postupně. Pruhy jdou za sebou jako schody – každé načítání čeká na předchozí.
  2. Klikni na Promise.all. Všechny pruhy začínají současně. Celkový čas = nejpomalejší uživatel.
  3. Pár pokusů zopakuj – časy se kvůli náhodnému zpoždění liší, ale paralelní verze vyhrává vždycky.

Co z toho plyne: Nezávislá načítání spouštěj najednou přes Promise.all. Postupně jen tehdy, když další krok potřebuje výsledek předchozího.

Načítám interaktivní část…

MetodaSplní se, když…Selže, když…
Promise.allse splní všechny (výsledky v pořadí)selže kterýkoli (hned)
Promise.allSettleddoběhnou všechny – úspěšně i neúspěšněnikdy
Promise.raceprvní doběhne úspěšněprvní doběhne chybou
Promise.anykterýkoli se splníselžou všechny
// allSettled – když nechceš, aby jedna chyba shodila všechno
const results = await Promise.allSettled([fetchUser(1), fetchUser(99)])
// [{ status: 'fulfilled', value: {…} }, { status: 'rejected', reason: Error }]
const found = results.filter((r) => r.status === 'fulfilled').map((r) => r.value)
// race – časový limit
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Vypršel čas')), 3000))
const user = await Promise.race([fetchUser(1), timeout])

7. fetch: skutečné volání serveru

V kurzu používáme falešné API (src/course/fakeApi.ts), aby vše fungovalo offline. Ve skutečné aplikaci se se serverem mluví přes vestavěnou funkci fetch:

async function loadUsers() {
const response = await fetch('https://api.example.com/users')
if (!response.ok) { // ⚠️ fetch NESELŽE při 404 nebo 500!
throw new Error(`Server vrátil ${response.status}`)
}
const users = await response.json() // tělo odpovědi → JS objekt (taky Promise)
return users
}
// Odeslání dat
await fetch('/api/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Ahoj' }), // objekt → text
})
⚠️ fetch selže jen při výpadku sítě
Když server odpoví „404 Nenalezeno“ nebo „500 Chyba serveru“, je to z pohledu fetch úspěšná odpověď. Vždy kontroluj response.ok (true pro stavy 200–299).

Zrušení požadavku: AbortController

const controller = new AbortController()
fetch('/api/search?q=react', { signal: controller.signal })
.then((r) => r.json())
.catch((e) => {
if (e.name === 'AbortError') return // zrušili jsme sami – není to chyba
throw e
})
controller.abort() // zruší probíhající požadavek

Hodí se třeba u vyhledávání: když uživatel píše dál, starý požadavek už nikoho nezajímá. V Reactu se tak ruší požadavky v úklidu efektu (lekce React 03).

8. Nejčastější chyby

// ❌ Zapomenutý await – máš Promise, ne data
const user = fetchUser(1)
user.name // undefined – Promise žádné name nemá
// ❌ await v forEach nečeká – forEach o Promise neví
ids.forEach(async (id) => {
await save(id)
})
console.log('Hotovo') // vypíše se HNED, ukládání ještě běží
// ✅ for…of (postupně) nebo Promise.all (najednou)
for (const id of ids) await save(id)
await Promise.all(ids.map((id) => save(id)))
// ❌ map s async vrátí pole Promise
const names = ids.map(async (id) => (await fetchUser(id)).name) // [Promise, Promise…]
// ✅ obal do Promise.all
const names = await Promise.all(ids.map(async (id) => (await fetchUser(id)).name))
// ❌ Chyba bez catch
async function load() {
const data = await fetchUser(99) // vyhodí chybu a nikdo ji nechytí
}

Ověř si to

Kvíz V jakém pořadí se vypíše: console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C')?
Kvíz Co vrátí async function f() { return 5 } po zavolání f()?
Kvíz Potřebuješ načíst 5 nezávislých uživatelů. Co je nejrychlejší?
Kvíz Server odpoví 404. Co udělá await fetch(url)?

Rozcvička

Výzva

Počkej a odpověz

Rozcvička

Dvě krátké async funkce: jedna chvíli počká, druhá načte uživatele z falešného API.

Zadání najdeš v komentářích v kódu níže – na začátku souboru a u míst označených TODO.

Načítám interaktivní část…

Výzva

Výzva

Načítání dat

StředníBonus · zdarma po přihlášení

Šest funkcí nad falešným API: čekání, načtení jednoho i víc uživatelů najednou, ošetření chyby a časový limit. Co přesně má která vracet, je v komentářích v kódu. Kontrola pod editorem chvíli trvá, protože API odpovídá se zpožděním.

🔓 Bonusová výzva – zdarma po přihlášení

Střední a těžké výzvy se odemknou, jakmile se přihlásíš. Stejně jako celý kurz jsou zdarma – stačí e-mail, žádné heslo ani platba.

Jak nakládáme s tvými údaji

Shrnutí

  • JavaScript má jedno vlákno. Pomalé věci se „objednávají“ a kód mezitím běží dál.
  • Pořadí: nejdřív celý synchronní kód, pak splněné Promise (mikroúlohy), pak setTimeout a události.
  • Promise je lísteček na budoucí výsledek: pending → fulfilled, nebo rejected.
  • async/await čte Promise jako normální kód. async funkce vždy vrací Promise.
  • Chyby chytej přes try/catch; finally proběhne vždy.
  • Nezávislé věci načítej najednou přes Promise.all. await ve forEach nefunguje.
  • fetch neselže při 404/500 – kontroluj response.ok. Rušit jde přes AbortController.
🧩 Odkud se berou věci, které tu nejsou definované (fetchUser, sleep)
fetchUser, sleep – ze souboru src/course/fakeApi.ts. Falešné API kurzu: data a funkce, které předstírají server (se zpožděním, občas i s chybou). Ve skutečné aplikaci by tu bylo volání fetch().
export interface User {
id: number
name: string
email: string
city: string
}
export async function fetchUser(id: number): Promise<User> {
await sleep(randomDelay())
const user = users.find((u) => u.id === id)
if (!user) throw new Error(`Uživatel ${id} neexistuje`)
return user
}
export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))