7.11 Generátory
Výuka
Co jsou generátory a proč existují?
Běžná funkce v JavaScriptu běží od začátku do konce najednou - vrátí hodnotu a skončí. Generátor je speciální typ funkce, která může pozastavit své vykonávání a později pokračovat tam, kde skončila.
Představ si to jako knihu: Běžná funkce je jako přečíst celou knihu najednou. Generátor je jako záložka - můžeš přestat číst, zavřít knihu, a později pokračovat přesně tam, kde jsi skončil.
K čemu jsou generátory užitečné?
- Líné vyhodnocování (lazy evaluation) - generuješ hodnoty až když je potřebuješ
- Nekonečné sekvence - můžeš vytvořit "nekonečný" seznam bez zahlcení paměti
- Řízení toku - pozastavení a pokračování výpočtu
- Iterátory na míru - vytvoření vlastních iterovatelných objektů
Syntaxe generátoru
function* nazevGeneratoru() {
yield hodnota1;
yield hodnota2;
return finalniHodnota;
}
Klíčové prvky:
function*- hvězdička označuje generátor (může být ifunction *nebofunction*)yield- "vydá" hodnotu a pozastaví funkcireturn- ukončí generátor s finální hodnotou
Jak generátor funguje?
1. Zavoláš generátor → vrátí iterátor (objekt), NE výsledek
2. Zavoláš .next() → spustí se až k prvnímu yield
3. Vrátí { value: hodnota, done: false }
4. Zavoláš .next() znovu → pokračuje od minulého yield k dalšímu
5. Když dojde na return → { value: finalniHodnota, done: true }
JavaScript
// Základní generátor
function* simpleGenerator() {
console.log("Začátek");
yield 1;
console.log("Po prvním yield");
yield 2;
console.log("Po druhém yield");
return 3;
}
const gen = simpleGenerator(); // Nevypíše nic! Jen vytvoří iterátor
console.log(gen.next()); // "Začátek" → { value: 1, done: false }
console.log(gen.next()); // "Po prvním yield" → { value: 2, done: false }
console.log(gen.next()); // "Po druhém yield" → { value: 3, done: true }
console.log(gen.next()); // { value: undefined, done: true }
// Iterace s for...of
function* colors() {
yield "červená";
yield "zelená";
yield "modrá";
}
for (const color of colors()) {
console.log(color);
}
// "červená", "zelená", "modrá"
// Spread operátor
const allColors = [...colors()];
// ["červená", "zelená", "modrá"]
// Nekonečný generátor
function* infiniteNumbers() {
let n = 0;
while (true) {
yield n++;
}
}
const nums = infiniteNumbers();
console.log(nums.next().value); // 0
console.log(nums.next().value); // 1
console.log(nums.next().value); // 2
// Pokračuje do nekonečna...
// Praktický příklad: range
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
for (const n of range(0, 10, 2)) {
console.log(n); // 0, 2, 4, 6, 8
}
// Předávání hodnot DO generátoru
function* conversation() {
const name = yield "Jak se jmenuješ?";
const hobby = yield `Ahoj ${name}! Co tě baví?`;
return `${name} má rád/a ${hobby}`;
}
const chat = conversation();
console.log(chat.next().value); // "Jak se jmenuješ?"
console.log(chat.next("Jana").value); // "Ahoj Jana! Co tě baví?"
console.log(chat.next("programování").value); // "Jana má rád/a programování"
// yield* - delegování na jiný iterátor
function* inner() {
yield 2;
yield 3;
}
function* outer() {
yield 1;
yield* inner(); // Deleguje na inner generátor
yield 4;
}
console.log([...outer()]); // [1, 2, 3, 4]
// Generátor jako ID generátor
function* idGenerator(prefix = "id") {
let id = 1;
while (true) {
yield `${prefix}_${id++}`;
}
}
const userIds = idGenerator("user");
console.log(userIds.next().value); // "user_1"
console.log(userIds.next().value); // "user_2"
// Fibonacci pomocí generátoru
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const fib = fibonacci();
for (let i = 0; i < 10; i++) {
console.log(fib.next().value);
}
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
TypeScript
// Typování generátoru: Generator<Yield, Return, Next>
// - Yield: typ hodnot které yield vrací
// - Return: typ hodnoty kterou return vrací
// - Next: typ hodnot přijímaných přes .next()
function* numberGenerator(): Generator<number, void, unknown> {
yield 1;
yield 2;
yield 3;
}
// Jednoduší zápis - TS často odvodí typy
function* colors(): Generator<string> {
yield "červená";
yield "zelená";
yield "modrá";
}
// Range s typy
function* range(start: number, end: number, step: number = 1): Generator<number> {
for (let i = start; i < end; i += step) {
yield i;
}
}
// Generátor s návratovou hodnotou
function* countdown(from: number): Generator<number, string, unknown> {
while (from > 0) {
yield from--;
}
return "Start!";
}
const counter = countdown(3);
console.log(counter.next()); // { value: 3, done: false }
console.log(counter.next()); // { value: 2, done: false }
console.log(counter.next()); // { value: 1, done: false }
console.log(counter.next()); // { value: "Start!", done: true }
// Generátor přijímající hodnoty
function* accumulator(): Generator<number, number, number> {
let total = 0;
while (true) {
const input: number = yield total;
total += input;
}
}
const acc = accumulator();
acc.next(); // Inicializace, { value: 0, done: false }
acc.next(5); // { value: 5, done: false }
acc.next(10); // { value: 15, done: false }
acc.next(3); // { value: 18, done: false }
// Async generátor
async function* fetchPages(urls: string[]): AsyncGenerator<Response> {
for (const url of urls) {
yield await fetch(url);
}
}
// Použití async generátoru
async function processPages() {
const urls = ["/api/page1", "/api/page2", "/api/page3"];
for await (const response of fetchPages(urls)) {
const data = await response.json();
console.log(data);
}
}
// Iterátor pomocí generátoru v třídě
class NumberRange implements Iterable<number> {
constructor(
private start: number,
private end: number
) {}
*[Symbol.iterator](): Generator<number> {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const range5to10 = new NumberRange(5, 10);
console.log([...range5to10]); // [5, 6, 7, 8, 9, 10]
// Typově bezpečný ID generátor
function* createIdGenerator<T extends string>(
prefix: T
): Generator<`${T}_${number}`, never, unknown> {
let id = 1;
while (true) {
yield `${prefix}_${id++}` as `${T}_${number}`;
}
}
const userIdGen = createIdGenerator("user");
const id1 = userIdGen.next().value; // "user_1" (typ: `user_${number}`)
Rozdíl JS vs TS
| JavaScript | TypeScript |
|---|---|
| Žádné typování generátoru | Generator |
yield vrací any |
Přesný typ yield hodnot |
.next() přijímá cokoliv |
Typová kontrola vstupů |
| Async generátor bez typů | AsyncGenerator |
// TypeScript rozlišuje 3 typy generátoru:
// Generator<Yield, Return, Next>
function* example(): Generator<string, number, boolean> {
// ^^^^^^ ^^^^^^ ^^^^^^^
// yield return .next() input
const input: boolean = yield "hello"; // yield vrací string
if (input) {
return 42; // return vrací number
}
return 0;
}
const gen = example();
gen.next(); // { value: "hello", done: false }
gen.next(true); // { value: 42, done: true }
Tip
Kdy použít generátory:
// 1. Líné zpracování velkých dat
function* processLargeFile(lines) {
for (const line of lines) {
yield line.trim().toUpperCase();
}
}
// Nezpracuje VŠECHNY řádky najednou - jen když potřebuješ
// 2. Stavové automaty
function* trafficLight() {
while (true) {
yield "červená";
yield "oranžová";
yield "zelená";
yield "oranžová";
}
}
// 3. Unikátní ID bez globální proměnné
const getId = (function*() {
let id = 0;
while (true) yield id++;
})();
getId.next().value; // 0
getId.next().value; // 1
yield* pro kompozici:
function* ones(n) {
for (let i = 0; i < n; i++) yield 1;
}
function* zeros(n) {
for (let i = 0; i < n; i++) yield 0;
}
function* pattern() {
yield* ones(3); // 1, 1, 1
yield* zeros(2); // 0, 0
yield* ones(2); // 1, 1
}
console.log([...pattern()]); // [1, 1, 1, 0, 0, 1, 1]
Async generátory pro streaming:
async function* streamData(url) {
const response = await fetch(url);
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield value;
}
}
Kvíz
Které výroky o generátorech jsou pravdivé?
❌ - Generátor při zavolání vrátí iterátor, ale nespustí se. Spustí se až při prvním .next()
✅ - yield pozastaví funkci, vrátí hodnotu a čeká na další .next()
✅ - Generátor je iterovatelný, takže funguje s for...of, spread operátorem atd.
❌ - Po return je generátor ukončen (done: true), další .next() vrací undefined
🎯 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ě