07.06 Promise.all
Výuka
Proč Promise.all?
Dosud jsme viděli sekvenční Promise řetězy - krok po kroku:
fetchUser()
.then(user => fetchSettings(user.id)) // Čeká na user
.then(settings => fetchArticles(settings.limit)) // Čeká na settings
Ale co když potřebuješ několik věcí najednou a jsou nezávislé?
Problém:
// ❌ Neefektivní - běží sekvenčně (30s celkem!)
fetchUser() // 10s
.then(() => fetchPosts()) // 10s
.then(() => fetchComments()); // 10s
// Celkem: 10s + 10s + 10s = 30 sekund 😭
Řešení: Promise.all() - spustí je paralelně:
// ✅ Efektivní - běží paralelně (10s celkem!)
Promise.all([
fetchUser(), // 10s
fetchPosts(), // 10s
fetchComments() // 10s
])
.then(([user, posts, comments]) => {
// Všechny tři hotové najednou!
});
// Celkem: max(10s, 10s, 10s) = 10 sekund! 🚀
Představ si to jako:
Jdeš do fastfoodu a objednáš si 3 věci najednou: burger, hranolky, nápoj.
❌ Sekvenčně (Promise chain):
1. Uvař burger → počkej → hotovo
2. Teď uvař hranolky → počkej → hotovo
3. Teď naplň nápoj → počkej → hotovo
Celkem: 15 minut
✅ Paralelně (Promise.all):
1. Uvař burger }
2. Uvař hranolky } Všechno najednou!
3. Naplň nápoj }
Počkáš, až je VŠECHNO hotové → dostaneš tác s CELOU objednávkou
Celkem: 5 minut (doba nejdelší položky)
Promise.all() je "gate" (brána):
- Brána se otevře AŽ když všechny Promises skončí
- Nezáleží na pořadí dokončení
- Dostaneš pole všech výsledků v původním pořadí
Jak Promise.all() funguje?
Signatura:
Promise.all([promise1, promise2, promise3, ...])
.then((results) => {
// results = [result1, result2, result3, ...]
});
Pravidla:
- Vstup: Pole Promises (nebo hodnot)
- Spustí všechny paralelně (neblokuje se)
- Čeká, až VŠECHNY skončí
- Výstup: Promise, který se vyřeší s polem výsledků
Důležité vlastnosti:
✅ Paralelní běh - Všechny Promises běží současně
✅ Pořadí výsledků - Pole výsledků má stejné pořadí jako vstupní pole (ne pořadí dokončení!)
✅ Fail-fast - Pokud jakýkoliv Promise selže, Promise.all() okamžitě selže (ostatní se dokončí, ale jejich výsledky se ignorují)
✅ Prázdné pole - Promise.all([]) se okamžitě vyřeší s []
Schéma:
Promise.all([p1, p2, p3])
│
├─ p1 ──┐
├─ p2 ──┤ Běží paralelně
└─ p3 ──┘
│
↓ (počká na VŠECHNY)
│
Promise<[result1, result2, result3]>
Fail-fast chování
Pokud JAKÝKOLIV Promise selže → celý Promise.all() okamžitě selže:
Promise.all([
Promise.resolve('OK'), // Uspěje
Promise.reject('CHYBA!'), // SELŽE!
Promise.resolve('Taky OK') // Uspěje
])
.then((results) => {
console.log('Nikdy se nedostaneš sem');
})
.catch((error) => {
console.error(error); // 'CHYBA!'
// Dostaneš JEN první chybu!
});
Co se stalo?
p2selhal →Promise.all()okamžitě rejectedp1ap3se dokončily, ale jejich výsledky se zahodily.catch()dostal pouze chybu z p2
Metafora:
Objednáš burger, hranolky, nápoj.
Burger se podaří ✅
Hranolky se spálí ❌
Nápoj se podaří ✅
→ Celá objednávka se zruší! Nedostaneš NIC.
Pořadí výsledků
Výsledky jsou VŽDY ve stejném pořadí jako vstupní pole (i když se Promises dokončí v jiném pořadí):
Promise.all([
delay(3000, 'Třetí dokončen'), // Dokončí se poslední
delay(1000, 'První dokončen'), // Dokončí se první
delay(2000, 'Druhý dokončen') // Dokončí se druhý
])
.then(([first, second, third]) => {
console.log(first); // 'Třetí dokončen'
console.log(second); // 'První dokončen'
console.log(third); // 'Druhý dokončen'
// Pořadí výsledků = pořadí v poli, NE pořadí dokončení!
});
Kdy použít Promise.all()?
✅ Použij Promise.all() když:
- Potřebuješ několik věcí najednou
- Jsou nezávislé (jedna nevyžaduje výsledek druhé)
- Potřebuješ všechny výsledky
- Chceš efektivitu (paralelní běh)
❌ Nepoužívej když:
- Kroky závisí na sobě (použij Promise chain)
- Potřebuješ jen jeden výsledek (použij
Promise.race()) - Chceš pokračovat i když něco selže (použij
Promise.allSettled())
Klíčové koncepty
- Gate pattern - Brána se otevře až když VŠECHNY Promises skončí
- Paralelní běh - Všechny Promises běží současně
- Pole výsledků - Výstup je pole v původním pořadí (ne pořadí dokončení)
- Fail-fast - První chyba okamžitě odmítne celý
Promise.all() - All-or-nothing - Buď dostaneš VŠECHNY výsledky, nebo ŽÁDNÝ
JavaScript
Základní použití Promise.all()
// Tři nezávislé async operace
function fetchUser() {
return new Promise((resolve) => {
setTimeout(() => resolve({ name: 'Jan', id: 1 }), 1000);
});
}
function fetchPosts() {
return new Promise((resolve) => {
setTimeout(() => resolve(['Post 1', 'Post 2']), 800);
});
}
function fetchComments() {
return new Promise((resolve) => {
setTimeout(() => resolve(['Comment 1', 'Comment 2']), 600);
});
}
// Spusť všechny paralelně
console.log('Start');
const startTime = Date.now();
Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])
.then(([user, posts, comments]) => {
const duration = Date.now() - startTime;
console.log('Vše hotovo za:', duration, 'ms'); // ~1000ms (nejdelší)
console.log('User:', user.name);
console.log('Posts:', posts.length);
console.log('Comments:', comments.length);
});
// Výstup (po ~1000ms):
// Vše hotovo za: 1001 ms
// User: Jan
// Posts: 2
// Comments: 2
Co se stalo?
- Všechny tři Promises běžely paralelně
- Celková doba: ~1000ms (nejdelší Promise), NE 1000+800+600=2400ms!
- Destructuring
[user, posts, comments]- rozbalení pole
Pořadí výsledků
// Promises se dokončí v různém pořadí
Promise.all([
new Promise(resolve => setTimeout(() => resolve('A'), 300)), // Dokončí 2.
new Promise(resolve => setTimeout(() => resolve('B'), 100)), // Dokončí 1.
new Promise(resolve => setTimeout(() => resolve('C'), 200)) // Dokončí 3.
])
.then(([first, second, third]) => {
console.log(first); // 'A' (ne 'B'!)
console.log(second); // 'B'
console.log(third); // 'C'
// Pořadí výsledků odpovídá pořadí v poli, NE pořadí dokončení!
});
// Výstup:
// A
// B
// C
Fail-fast chování
Promise.all([
Promise.resolve('Úspěch 1'),
Promise.reject('Chyba!'), // První chyba!
Promise.resolve('Úspěch 2')
])
.then((results) => {
console.log('Nikdy se nedostaneš sem');
})
.catch((error) => {
console.error('Zachycená chyba:', error); // 'Chyba!'
});
// Výstup:
// Zachycená chyba: Chyba!
Co se stalo?
- Druhý Promise (rejected) způsobil okamžité selhání
Promise.all() - První a třetí Promise se ignorovaly
.catch()dostal pouze první chybu
Vícenásobné chyby
// Co když selže více Promises?
Promise.all([
Promise.reject('Chyba 1'), // První chyba
Promise.reject('Chyba 2'), // Druhá chyba
Promise.resolve('OK')
])
.catch((error) => {
console.error(error); // 'Chyba 1'
// Dostaneš JEN první chybu!
// 'Chyba 2' se ignoruje
});
// Výstup:
// Chyba 1
Prázdné pole
// Prázdné pole → okamžité vyřešení
Promise.all([])
.then((results) => {
console.log(results); // []
console.log('Okamžitě vyřešeno!');
});
// Výstup (OKAMŽITĚ):
// []
// Okamžitě vyřešeno!
Promise.all() s hodnotami (ne-Promises)
// Můžeš míchat Promises a hodnoty
Promise.all([
Promise.resolve(42),
'hello', // Není Promise - automaticky se zabalí
100, // Také ne Promise
Promise.resolve('world')
])
.then(([a, b, c, d]) => {
console.log(a); // 42
console.log(b); // 'hello'
console.log(c); // 100
console.log(d); // 'world'
});
Co se stalo?
- Ne-Promise hodnoty se automaticky zabalí do
Promise.resolve(hodnota) - Funguje to, ale nedává smysl -
Promise.all()je pro async operace!
Reálný příklad - Paralelní HTTP requesty
// Simulace API requestů
function fetchUserData(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ userId, name: 'Jan Novák' });
}, 500);
});
}
function fetchUserPosts(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 1, title: 'Post 1' },
{ id: 2, title: 'Post 2' }
]);
}, 300);
});
}
function fetchUserFollowers(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(['follower1', 'follower2', 'follower3']);
}, 400);
});
}
// Načti všechny data paralelně
const userId = 123;
Promise.all([
fetchUserData(userId),
fetchUserPosts(userId),
fetchUserFollowers(userId)
])
.then(([userData, posts, followers]) => {
console.log('User:', userData.name);
console.log('Posts count:', posts.length);
console.log('Followers count:', followers.length);
// Vše načteno za ~500ms místo ~1200ms!
})
.catch((error) => {
console.error('Selhalo načtení dat:', error);
});
// Výstup (po ~500ms):
// User: Jan Novák
// Posts count: 2
// Followers count: 3
TypeScript
TypeScript přidává typovou bezpečnost pro výsledky Promise.all().
Typované Promise.all()
// TypeScript automaticky odvodí typy
Promise.all([
Promise.resolve(42), // Promise<number>
Promise.resolve('hello'), // Promise<string>
Promise.resolve(true) // Promise<boolean>
])
.then(([num, str, bool]) => {
// TS ví, že:
// num: number
// str: string
// bool: boolean
console.log(num.toFixed(2)); // ✅ OK
console.log(str.toUpperCase()); // ✅ OK
console.log(bool ? 'yes' : 'no'); // ✅ OK
});
TypeScript odvodí typ:
Promise.all([...]) → Promise<[T1, T2, T3, ...]>
Typované API requesty
interface User {
id: number;
name: string;
}
interface Post {
id: number;
title: string;
content: string;
}
interface Comment {
id: number;
text: string;
}
function fetchUser(): Promise<User> {
return Promise.resolve({ id: 1, name: 'Jan' });
}
function fetchPosts(): Promise<Post[]> {
return Promise.resolve([
{ id: 1, title: 'Post 1', content: 'Content 1' }
]);
}
function fetchComments(): Promise<Comment[]> {
return Promise.resolve([
{ id: 1, text: 'Comment 1' }
]);
}
// TS odvodí typy v poli výsledků
Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])
.then(([user, posts, comments]) => {
// TS ví, že:
// user: User
// posts: Post[]
// comments: Comment[]
console.log(user.name); // ✅ OK
console.log(posts[0].title); // ✅ OK
console.log(comments[0].text); // ✅ OK
// console.log(user.email); // ❌ Error - User nemá email
});
Explicitní typy
// Můžeš explicitně zadat typ
const promises: [Promise<number>, Promise<string>, Promise<boolean>] = [
Promise.resolve(42),
Promise.resolve('hello'),
Promise.resolve(true)
];
Promise.all(promises)
.then(([num, str, bool]) => {
// TS ví přesné typy
});
Error handling s typy
class ApiError extends Error {
constructor(public code: number, message: string) {
super(message);
}
}
Promise.all([
fetch('/api/user'),
fetch('/api/posts')
])
.then(([userRes, postsRes]) => {
// Zpracuj odpovědi
})
.catch((error: unknown) => {
// TS vynutí kontrolu typu
if (error instanceof ApiError) {
console.error('API Error:', error.code, error.message);
} else if (error instanceof Error) {
console.error('Error:', error.message);
} else {
console.error('Unknown error');
}
});
Generická funkce s Promise.all()
// Generická funkce pro paralelní fetching
async function fetchAll<T extends any[]>(
...fetchers: { [K in keyof T]: () => Promise<T[K]> }
): Promise<T> {
return Promise.all(fetchers.map(f => f())) as Promise<T>;
}
// Použití
fetchAll(
() => fetch('/api/user').then(r => r.json()),
() => fetch('/api/posts').then(r => r.json())
).then(([user, posts]) => {
// TS odvodí typy
});
Rozdíl JS vs TS
JavaScript:
Promise.all()bez typů- Nevíš, jaké typy dostaneš v poli výsledků
- Musíš si pamatovat pořadí Promises
- Chyby až za běhu
TypeScript:
Promise<[T1, T2, T3, ...]>- přesné typy pro každý výsledek- Autocomplete v IDE pro výsledky
- Kontrola typů při kompilaci
- Ví pořadí a typy všech výsledků
Příklad:
// JS - nevíš co dostaneš
Promise.all([fetchUser(), fetchPosts()])
.then(([user, posts]) => {
console.log(user.name); // Může selhat za běhu
});
// TS - víš přesně
Promise.all([fetchUser(), fetchPosts()])
.then(([user, posts]) => {
// TS ví: user: User, posts: Post[]
console.log(user.name); // ✅ TS ví, že má name
// console.log(user.email); // ❌ Error - nemá email
});
Tip
💡 Destructuring pro čitelnost:
// ❌ Těžko čitelné
Promise.all([fetchUser(), fetchPosts(), fetchComments()])
.then((results) => {
const user = results[0];
const posts = results[1];
const comments = results[2];
// ...
});
// ✅ Čitelné s destructuring
Promise.all([fetchUser(), fetchPosts(), fetchComments()])
.then(([user, posts, comments]) => {
// Jasné názvy hned!
});
💡 Paralelně vs Sekvenčně:
// ❌ Sekvenčně - POMALÉ (30s)
fetchUser()
.then(() => fetchPosts()) // Čeká 10s
.then(() => fetchComments()); // Čeká dalších 10s
// ✅ Paralelně - RYCHLÉ (10s)
Promise.all([
fetchUser(), // Všechny běží
fetchPosts(), // současně!
fetchComments()
]);
💡 Kdy NEPOUŽÍVAT Promise.all():
// ❌ Kroky závisí na sobě - NELZE paralelizovat!
Promise.all([
fetchUser(),
fetchSettings(user.id), // Potřebuje user! Ale user ještě není!
fetchArticles(settings.limit) // Potřebuje settings!
]);
// ✅ Použij Promise chain
fetchUser()
.then(user => fetchSettings(user.id))
.then(settings => fetchArticles(settings.limit));
💡 Fail-fast → Vždy .catch():
// ✅ Vždy přidej .catch()
Promise.all([p1, p2, p3])
.then(handleSuccess)
.catch(handleError); // POVINNÉ! Jinak se chyba "polkne"
💡 Prázdné pole = okamžité vyřešení:
Promise.all([]).then(() => {
console.log('Okamžitě!');
});
// Ekvivalentní s:
Promise.resolve([]).then(() => {
console.log('Okamžitě!');
});
💡 Pokud potřebuješ pokračovat i při chybách:
// Promise.all() selže na první chybě
// Pokud chceš pokračovat i když něco selže:
// ✅ ES2020: Promise.allSettled()
Promise.allSettled([p1, p2, p3])
.then((results) => {
// results = [
// { status: 'fulfilled', value: ... },
// { status: 'rejected', reason: ... },
// ...
// ]
});
Kvíz
Které výroky o Promise.all() jsou pravdivé?
✅ - Promise.all() spustí všechny Promises současně (paralelně) - nečeká na dokončení jednoho před spuštěním dalšího
❌ - Výsledky jsou v původním pořadí z pole, NE v pořadí dokončení! Promise.all([p1, p2, p3]) vrátí [result1, result2, result3] bez ohledu na to, který se dokončil první.
✅ - Fail-fast - první chyba způsobí okamžité selhání celého Promise.all(), ostatní výsledky se zahodí
❌ - Promise.all([]) se okamžitě vyřeší s [] (prázdné pole)
🎯 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ě