Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

7.2 Callbacks

Výuka

Co je callback?

Callback je funkce, kterou předáš jako argument do jiné funkce. Ta ji pak zavolá později - obvykle až dokončí nějakou asynchronní operaci.

Představ si to jako:

Jdeš k lékaři a řekneš: "Potřebuju výsledky testů. Až budou hotové (což může trvat), zavolej mi na tenhle telefon (callback) a povím ti, co s tím dál."

Doktor neblokuje tvůj den - ty mezitím můžeš dělat jiné věci. Až jsou výsledky hotové, callback se zavolá a ty zpracuješ informaci.

Proč callbacks?

V asynchronním kódu nemůžeš okamžitě dostat výsledek, protože operace trvá nějakou dobu (síť, disk, timer...). Potřebuješ způsob, jak říct: "Až to bude hotové, zavolej tuhle funkci s výsledkem."

Jak to funguje:

1. Spustíš async operaci (např. čtení souboru)
2. Předáš callback: "až bude hotovo, zavolej tuhle funkci"
3. Program pokračuje dál (NEČEKÁ!)
4.  operace skončí  zavolá se callback s výsledkem
5. Callback zpracuje výsledek

Callbacks jsou VŠUDE v JavaScriptu

Callbacks nejsou jen pro asynchronní kód! Používají se i synchronně:

// Array metody - callbacks!
[1, 2, 3].map(num => num * 2);      // callback: num => num * 2
[1, 2, 3].filter(num => num > 1);   // callback: num => num > 1

// Event listeners - callbacks!
button.addEventListener('click', () => {
  console.log('Kliknuto!');  // callback se zavolá při kliknutí
});

Rozdíl:

  • Synchronní callback - zavolá se HNED (map, filter, forEach)
  • Asynchronní callback - zavolá se POZDĚJI (setTimeout, readFile, fetch)

Continuation (pokračování programu)

Callback můžeš chápat jako pokračování programu. Rozděluje program na dvě části:

┌─────────────────┐
  Část 1 (NOW)     Provede se HNED
  - hlavní kód   
└────────┬────────┘
         
         
   [ČEKÁNÍ na async operaci]
         
         
┌────────┴────────┐
  Část 2 (LATER)   Provede se  později
  - callback     
└─────────────────┘

Příklad:

// A (NOW)
setTimeout(() => {
  // C (LATER)
}, 1000);
// B (NOW)

Pořadí: A → B → (čekání) → C

Callback () => { // C } je druhá polovina programu - pokračování, které se provede až za sekundu.

Jak náš mozek přemýšlí vs jak fungují callbacks

Problém: Náš mozek plánuje synchronně (krok po kroku):

"Nejdřív udělám A, pak B, pak C."

Ale callbacks nás nutí přemýšlet asynchronně:

"Udělám A, pak nastartuju B (který trvá), mezitím udělám C, a až B skončí, zavolá se můj callback s výsledkem B..."

To je těžké! Proto je async kód s callbacky náročný na čtení a pochopení.

Srovnání:

// Synchronní - jasné pořadí (mozek tohle chápe)
z = x;
x = y;
y = z;

// Asynchronní - pořadí se "rozpadá"
doA(() => {
  doC();
  doD(() => {
    doF();
  });
  doE();
});
doB();

// Pořadí: A → B → C → D → E → F  (WTF?!)

JavaScript

Synchronní callback (okamžité zavolání)

// Funkce přijímá callback jako parametr
function doSomething(callback) {
  const result = 5 + 3;
  callback(result);  // Zavolá callback HNED
}

// Použití
doSomething((result) => {
  console.log('Výsledek:', result);  // 8
});
console.log('Pokračuji dál...');

// Výstup:
// Výsledek: 8
// Pokračuji dál...

Co se stalo? Callback se zavolal synchronně - HNED, během běhu doSomething().

Asynchronní callback (pozdější zavolání)

// Funkce s asynchronním callbackem
function fetchData(callback) {
  setTimeout(() => {
    const data = { name: 'Jan', age: 25 };
    callback(data);  // Zavolá callback AŽ PO 1 sekundě
  }, 1000);
}

// Použití
fetchData((data) => {
  console.log('Data načtena:', data);
});
console.log('Pokračuji dál...');

// Výstup (okamžitě):
// Pokračuji dál...
// (po 1s): Data načtena: { name: 'Jan', age: 25 }

Co se stalo?

  1. fetchData spustil timeout a VRÁTIL SE OKAMŽITĚ
  2. Program pokračoval dál → console.log('Pokračuji dál...')
  3. Až za sekundu timeout zavolal callback

Error-first callback pattern (Node.js konvence)

V Node.js se používá konvence: první parametr callbacku je error (pokud nastala chyba), druhý je data (pokud vše OK).

Proč? Musíš řešit dvě věci:

  • ✅ Co dělat, když operace uspěje (data)
  • ❌ Co dělat, když operace selže (error)
// Error-first callback pattern
function readFile(filename, callback) {
  setTimeout(() => {
    if (filename === 'error.txt') {
      // Chyba - první parametr je Error
      callback(new Error('Soubor nenalezen'), null);
    } else {
      // Úspěch - první parametr je null
      callback(null, 'Obsah souboru');
    }
  }, 1000);
}

// Použití
readFile('data.txt', (err, data) => {
  if (err) {
    console.error('Chyba:', err.message);
    return;  // Skonči, nezpracovávej data
  }
  console.log('Data:', data);
});

Konvence:

  • callback(error, null) - chyba nastala
  • callback(null, data) - úspěch, máme data

Vždy nejdřív kontroluj error!

Reálné příklady callbacků

// 1. setTimeout (časovač)
setTimeout(() => {
  console.log('Po 2 sekundách');
}, 2000);

// 2. addEventListener (události v prohlížeči)
button.addEventListener('click', (event) => {
  console.log('Kliknuto!', event);
});

// 3. Array metody (synchronní callbacks)
const numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
  console.log(num * 2);
});

const doubled = numbers.map((num) => num * 2);
// [2, 4, 6, 8, 10]

const evens = numbers.filter((num) => num % 2 === 0);
// [2, 4]

// 4. HTTP request (fetch s then - předchůdce async/await)
fetch('/api/users')
  .then(response => response.json())
  .then(users => {
    console.log('Users:', users);
  });

TypeScript

TypeScript přidává typy pro callbacks, takže víš přesně, co callback dostane a co má vrátit.

Typované callback funkce

// Definice typu pro callback
type Callback<T> = (data: T) => void;

// Callback který dostane číslo
type NumberCallback = (num: number) => void;

// Callback který dostane string
type StringCallback = (str: string) => void;

// Použití v funkci
function fetchUser(id: number, callback: Callback<User>): void {
  setTimeout(() => {
    const user: User = { id, name: 'Jan', age: 25 };
    callback(user);  // TS ví, že callback dostane User
  }, 1000);
}

// Použití
fetchUser(1, (user: User) => {
  console.log(user.name);  // TS ví, že user má property name
  // console.log(user.email); // ❌ Error - User nemá email
});

Error-first callback s typy

// Typ pro error-first callback
type ErrorCallback<T> = (error: Error | null, data: T | null) => void;

function loadData(
  filename: string,
  callback: ErrorCallback<string>
): void {
  setTimeout(() => {
    if (filename.endsWith('.txt')) {
      callback(null, 'Data loaded');  // Úspěch
    } else {
      callback(new Error('Invalid file'), null);  // Chyba
    }
  }, 500);
}

// Použití
loadData('data.txt', (err, data) => {
  if (err) {
    console.error(err.message);
    return;
  }
  // TS ví, že data je string (pokud není null)
  console.log(data.toUpperCase());  // ✅ OK
});

Generický callback

// Generická funkce s callbackem
function processAsync<T>(
  value: T,
  callback: (result: T) => void
): void {
  setTimeout(() => callback(value), 100);
}

// TS automaticky odvodí typ T
processAsync<number>(42, (result) => {
  console.log(result * 2);  // TS ví, že result je number
});

processAsync<string>('hello', (result) => {
  console.log(result.toUpperCase());  // TS ví, že result je string
});

Interface pro User (pro příklady výše)

interface User {
  id: number;
  name: string;
  age: number;
}

Rozdíl JS vs TS

JavaScript:

  • Callbacks bez typů - nevíš, co callback dostane
  • Žádná kontrola v IDE
  • Chyby až za běhu programu

TypeScript:

  • Typované callbacks - přesně víš, co callback dostane a vrátí
  • Autocomplete v IDE pro parametry callbacku
  • Kontrola typů PŘED spuštěním
  • Bezpečnější kód
// JS - nevíš co dostaneš
fetchData((data) => {
  console.log(data.name);  // Možná chyba za běhu (pokud data nemá name)
});

// TS - víš přesně
fetchData((data: User) => {
  console.log(data.name);  // ✅ TS ví, že má name
  // console.log(data.email); // ❌ Error - User nemá email
});

Tip

💡 Error-first pattern (Node.js konvence):

// Konvence: první parametr = error
function operation(callback) {
  if (/* něco se pokazilo */) {
    callback(new Error('Popis chyby'), null);
  } else {
    callback(null, data);
  }
}

// Použití - VŽDY nejdřív zkontroluj error!
operation((err, data) => {
  if (err) return console.error(err);  // Skonči při chybě
  console.log(data);  // Zpracuj data
});

💡 Callback vs Handler:

// Callback - zavolá se JEDNOU
setTimeout(callback, 1000);
readFile('file.txt', callback);

// Handler - může být zavolán VÍCEKRÁT
button.addEventListener('click', handler);
websocket.on('message', handler);

💡 Arrow functions pro callbacks (kratší zápis):

// Delší zápis (klasická funkce)
setTimeout(function() {
  console.log('Hotovo');
}, 1000);

// Kratší zápis (arrow function)
setTimeout(() => {
  console.log('Hotovo');
}, 1000);

// Jednořádkový (nejkratší)
setTimeout(() => console.log('Hotovo'), 1000);

💡 Callback "hell" bude v další lekci:

Callbacks mají velký problém - vnořování. Když potřebuješ několik async operací za sebou:

// Pyramid of doom (callback hell) - PŘÍŠTĚ!
readFile('file1.txt', (err, data1) => {
  readFile('file2.txt', (err, data2) => {
    readFile('file3.txt', (err, data3) => {
      // Už nevíš, kde jsi... 😵
    });
  });
});

To si ukážeme v 7.3 Callback Hell.


Kvíz

Které výroky jsou pravdivé?

- Callback = funkce jako argument, kterou někdo jiný zavolá

- Callbacks se používají i synchronně (map, forEach, filter, reduce)

- Node.js konvence: callback(error, data) - error je vždy první

- TS často automaticky odvodí typ callbacku z kontextu (type inference)

🎯 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 →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

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


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě