Synchronní vs. Asynchronní kód

Synchronní kód se vykonává řádek po řádku — každý řádek čeká na předchozí. Asynchronní kód umožňuje "odložit" časově náročné operace (síťové požadavky, čtení souborů) a pokračovat dál.

Synchronní — blokuje celé vlákno:
Vlákno
JS kód
čeká na API
zpracování
Asynchronní — vlákno je volné:
JS vlákno
kód
další kód
zpracování
API call
síťový požadavek (čeká na pozadí)

JavaScript používá Event Loop — single-threaded model, kde asynchronní operace (setTimeout, Fetch, I/O) jsou zpracovány na pozadí a jejich výsledky jsou zařazeny do fronty callbacků.

💡
Evoluce async v JS: Callbacks (ES5) → Promises (ES6/2015) → async/await (ES2017). Každá generace řeší problémy té předchozí. Dnes používáme primárně async/await.
Kapitola 1 / 8 Další: Callback →

Callback a Callback Hell

Callback je funkce předaná jako argument jiné funkci — zavolá se po dokončení operace. Je to nejstarší async vzor v JS.

// setTimeout — nejjednodušší async operace
console.log("1. Start");
setTimeout(() => {
  console.log("3. Po 1 sekundě");
}, 1000);
console.log("2. Hned po setTimeout");
// Výstup: 1, 2, 3 (ne 1, 3, 2!)

// Praktický callback — načtení dat (starý styl)
function nactiUzivatele(id, callback) {
  setTimeout(() => {
    const uzivatel = { id, jmeno: "Jana" };
    callback(null, uzivatel); // (error, data) konvence
  }, 500);
}

nactiUzivatele(1, (err, uzivatel) => {
  if (err) return console.error(err);
  console.log(uzivatel.jmeno);
});

Callback Hell — proč promises vznikly

// ❌ Callback hell — těžko čitelné, těžko laditelné
nactiUzivatele(1, (err, user) => {
  if (err) handleErr(err);
  nactiObjednavky(user.id, (err, orders) => {
    if (err) handleErr(err);
    nactiProdukty(orders[0].id, (err, products) => {
      if (err) handleErr(err);
      zobrazVysledek(products); // 3+ úrovně vnoření!
    });
  });
});
Kapitola 2 / 8 Další: Promise →

Promise

Promise je objekt reprezentující budoucí výsledek asynchronní operace. Může být ve třech stavech:

Pending
Čeká na dokončení operace
Fulfilled
Operace proběhla úspěšně
Rejected
Operace selhala s chybou
// Vytvoření Promise
const mojPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const uspech = true;
    if (uspech) resolve("Data načtena!");
    else reject(new Error("Chyba načítání"));
  }, 1000);
});

// Konzumace Promise — .then() / .catch() / .finally()
mojPromise
  .then(data => console.log(data))        // "Data načtena!"
  .catch(err => console.error(err.message))
  .finally(() => console.log("Hotovo"));  // vždy

// Promise chaining — řeší callback hell
nactiUzivatele(1)
  .then(user => nactiObjednavky(user.id))
  .then(orders => nactiProdukty(orders[0].id))
  .then(products => zobrazVysledek(products))
  .catch(err => handleErr(err)); // jeden catch pro vše!

// Promise.all — paralelní požadavky
const [users, products] = await Promise.all([
  fetch('/api/users').then(r => r.json()),
  fetch('/api/products').then(r => r.json())
]);

// Promise.allSettled — i když některé selžou
const vysledky = await Promise.allSettled([p1, p2, p3]);
vysledky.forEach(r => {
  if (r.status === 'fulfilled') console.log(r.value);
  else console.error(r.reason);
});

🧠 Kvíz: Co je rozdíl mezi Promise.all() a Promise.allSettled()?

Kapitola 3 / 8 Další: async/await →

async / await

async/await je syntaktický cukr nad Promises — kód vypadá synchronně, ale chová se asynchronně. Dnes je to standardní způsob práce s async operacemi.

// async funkce vždy vrátí Promise
async function nactiData() {
  return "data"; // ekvivalent: return Promise.resolve("data")
}

// await pozastaví funkci (ne celý JS!) dokud Promise nedosáhne settled stavu
async function hlavniFunkce() {
  const uzivatel = await nactiUzivatele(1);
  const objednavky = await nactiObjednavky(uzivatel.id);
  const produkty = await nactiProdukty(objednavky[0].id);
  return produkty;
  // Čitelné jako synchronní kód!
}

// Paralelní volání s await
async function paralelne() {
  // ❌ Sekvenční (pomalé — čeká postupně)
  const a = await fetchA();
  const b = await fetchB(); // čeká až skončí fetchA

  // ✅ Paralelní (rychlé)
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
}

// Top-level await (moderní ES2022, v modulech)
const data = await fetch('/api/data').then(r => r.json());
Živý editor — simulace async operací

🧠 Kvíz: Co se stane, pokud použijete await mimo async funkci?

Kapitola 4 / 8 Další: Fetch API →

Fetch API

Fetch je moderní nativní API pro HTTP požadavky — nahrazuje starý XMLHttpRequest. Vrací Promise.

// GET — načtení dat
async function nactiPrispevky() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');

  // Fetch NESELHÁVÁ při 4xx/5xx — vždy zkontrolujte status!
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  const data = await response.json(); // parsuje JSON
  return data;
}

// POST — odeslání dat
async function vytvorPrispevek(data) {
  const response = await fetch('/api/posts', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ' + token,
    },
    body: JSON.stringify(data),
  });
  return response.json();
}

// PUT, PATCH, DELETE — stejný pattern, jiná method
async function smazPrispevek(id) {
  await fetch(`/api/posts/${id}`, { method: 'DELETE' });
}

// Query parametry
const params = new URLSearchParams({ page: 1, limit: 10 });
fetch(`/api/posts?${params}`);

// Response typy
response.json()     // JSON → objekt
response.text()     // text/HTML
response.blob()     // binární (obrázky)
response.headers.get('Content-Type')
Živý editor — volání veřejného API (JSONPlaceholder)

Error Handling v async kódu

Chyby v async kódu se zpracovávají pomocí try/catch — ekvivalent .catch() u promises, ale čitelnější.

// try/catch/finally s async/await
async function nacteniDat(url) {
  try {
    const response = await fetch(url);

    // fetch nevyhodí chybu pro 4xx/5xx!
    if (!response.ok) {
      throw new Error(`API chyba: ${response.status}`);
    }

    const data = await response.json();
    return data;

  } catch (error) {
    // Zachytí: síťové chyby (offline), JSON parse chyby, naše throw
    if (error instanceof TypeError) {
      console.error('Síťová chyba:', error.message);
    } else {
      console.error('Obecná chyba:', error.message);
    }
    return null; // nebo throw pro propagaci výše

  } finally {
    // Vždy proběhne — ideální pro: skrytí loaderu, cleanup
    hideLoader();
  }
}

// Vlastní chybové třídy
class APIError extends Error {
  constructor(status, message) {
    super(message);
    this.name = 'APIError';
    this.status = status;
  }
}

// Utility wrapper — čistší kód bez try/catch všude
async function safeAwait(promise) {
  try {
    const data = await promise;
    return [null, data];
  } catch (error) {
    return [error, null];
  }
}

// Použití:
const [err, data] = await safeAwait(fetch('/api/data'));
if (err) return handleError(err);
// data jsou garantovaně validní

🧠 Kvíz: Fetch vrátí Response s status: 404. Vyhodí to automaticky chybu (rejectuje Promise)?

Kapitola 6 / 8 Další: Cvičení →

Praktické cvičení — GitHub API klient

Napište mini aplikaci, která načte data o GitHub uživateli z veřejného API (https://api.github.com/users/JMENO) a zobrazí avatar, jméno, bio, počet repozitářů a followers. Přidejte loading stav a error handling.

📋
Checklist: Input + tlačítko pro zadání jména, async function nactiUzivatele(), try/catch, if (!response.ok) check, loading stav (disable tlačítka + spinner text), zobrazení dat přes innerHTML.
Vaše řešení
🏅

Odznak: Async Mistr

Zvládáte Promise, async/await, Fetch API a error handling.

Kapitola 7 / 8 Další: Taháček →

Taháček — rychlá reference

async/await šablona

async function nactiData(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return await res.json();
  } catch (err) {
    console.error(err);
    return null;
  }
}

Fetch — POST

const res = await fetch('/api/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ klic: 'hodnota' }),
});
const data = await res.json();

Paralelní volání

// ✅ Paralelně (rychlé)
const [a, b] = await Promise.all([fetchA(), fetchB()]);

// I při částečných selháních
const results = await Promise.allSettled([p1, p2, p3]);

Zlatá pravidla

  • ✅ Vždy try/catch u async funkcí
  • ✅ Vždy zkontrolujte response.ok po fetch
  • ✅ Paralelní volání pomocí Promise.all()
  • finally pro cleanup (schování loaderu)
  • ❌ Nikdy await v cyklu pokud lze paralelizovat
  • ❌ Zapomínat na await — vrátí Promise, ne hodnotu