Appearance
Kapitel 11: Promise (Asynchrone Programmierung)
11.1 Was ist Callback Hell?
❌ Das Callback-Hell Problem
Callback Hell (auch Pyramid of Doom genannt) entsteht, wenn mehrere asynchrone Operationen verschachtelt sind.
javascript
// ❌ Callback Hell (Pyramid of Doom)
getUser(userId, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
getAuthor(comments[0].authorId, function(author) {
console.log(author);
// ... noch tiefer? 😱
}, function(error) {
console.error(error);
});
}, function(error) {
console.error(error);
});
}, function(error) {
console.error(error);
});
}, function(error) {
console.error(error);
});Probleme:
- 🚫 Schwer zu lesen
- 🚫 Schwer zu warten
- 🚫 Fehlerbehandlung ist chaotisch
- 🚫 "Callback-Hell"
11.2 Promise Grundlagen
📦 Was ist ein Promise?
Ein Promise ist ein Objekt, das einen asynchronen Vorgang repräsentiert. Es kann drei Zustände haben:
| Zustand | Beschreibung |
|---|---|
| Pending (Anstehend) | Vorgang läuft noch |
| Fulfilled (Erfüllt) | Vorgang erfolgreich abgeschlossen |
| Rejected (Abgelehnt) | Vorgang fehlgeschlagen |
javascript
// Syntax
const promise = new Promise((resolve, reject) => {
// Asynchrone Operation
if (/* Erfolg */) {
resolve(ergebnis); // In Fulfilled-Zustand
} else {
reject(fehler); // In Rejected-Zustand
}
});🎯 Einfaches Beispiel
javascript
// Promise erstellen
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("Daten erfolgreich geladen! ✅");
} else {
reject("Fehler beim Laden! ❌");
}
}, 1000);
});
// Promise verwenden
myPromise
.then(result => console.log(result))
.catch(error => console.error(error));Ausgabe (nach 1 Sekunde):
Daten erfolgreich geladen! ✅11.3 then() catch() finally()
✅ then() - Bei Erfolg
javascript
const promise = new Promise((resolve, reject) => {
resolve("Erfolg!");
});
promise.then(result => {
console.log(result); // "Erfolg!"
});Verkettung (Chaining):
javascript
promise
.then(result => result + " 🎉")
.then(result => console.log(result)) // "Erfolg! 🎉"
.then(() => "Nächster Schritt")
.then(result => console.log(result)); // "Nächster Schritt"❌ catch() - Bei Fehler
javascript
const promise = new Promise((resolve, reject) => {
reject("Fehler!");
});
promise
.then(result => console.log(result))
.catch(error => console.error(error)); // "Fehler!"Fehlerbehandlung in der Kette:
javascript
promise
.then(result => {
throw new Error("Ein Fehler!");
})
.then(result => console.log("Wird nicht ausgeführt"))
.catch(error => console.error(error)); // "Ein Fehler!"🔄 finally() - Immer ausführen
javascript
const promise = new Promise((resolve, reject) => {
resolve("Erfolg!");
});
promise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => {
console.log("Bereinigung (immer ausgeführt)");
});Praxisbeispiel:
javascript
function fetchData(url) {
console.log("Laden..."); // Loading...
return fetch(url)
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => {
console.log("Laden beendet"); // Loading finished
});
}11.4 Promise.all() - Parallele Anfragen
📦 Was macht Promise.all()?
Promise.all() führt mehrere Promises parallel aus und gibt die Ergebnisse in einem Array zurück.
javascript
// Syntax
Promise.all([promise1, promise2, ...])
.then(results => { /* Alle erfolgreich */ })
.catch(error => { /* Mindestens eines fehlgeschlagen */ });🎯 Beispiel: Mehrere API-Aufrufe parallel
javascript
const fetchUser = fetch("https://api.example.com/user/1").then(r => r.json());
const fetchPosts = fetch("https://api.example.com/user/1/posts").then(r => r.json());
const fetchComments = fetch("https://api.example.com/user/1/comments").then(r => r.json());
Promise.all([fetchUser, fetchPosts, fetchComments])
.then(([user, posts, comments]) => {
console.log("User:", user);
console.log("Posts:", posts);
console.log("Comments:", comments);
})
.catch(error => console.error("Ein Fehler ist aufgetreten:", error));Vorteil: Parallele Ausführung (schneller!)
⚠️ Verhalten bei Fehlern
javascript
const p1 = Promise.resolve(1);
const p2 = Promise.reject("Fehler");
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3])
.then(results => console.log(results))
.catch(error => console.error(error)); // "Fehler" ❌Wichtig: Wenn ein Promise fehlschlägt, wird sofort der catch()-Block ausgeführt.
11.5 Promise.race() - Das schnellste gewinnt
🏎️ Was macht Promise.race()?
Promise.race() gibt das Ergebnis des ersten Promises, das abgeschlossen wird (egal ob Erfolg oder Fehler).
javascript
// Syntax
Promise.race([promise1, promise2, ...])
.then(result => { /* Das schnellste gewinnt */ })
.catch(error => { /* Das schnellste schlägt fehl */ });🎯 Beispiel: Timeout-Simulation
javascript
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => resolve("Daten geladen"), 2000);
});
const timeout = new Promise((resolve, reject) => {
setTimeout(() => reject("Timeout!"), 1000);
});
Promise.race([fetchData, timeout])
.then(result => console.log(result))
.catch(error => console.error(error)); // "Timeout!" ⏰11.6 Praxis: API-Anfragen simulieren
🌐 Beispiel 1: Einfache API-Simulation
javascript
// API-Aufruf simulieren
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: "Max", email: "max@example.com" });
} else {
reject("Ungültige ID");
}
}, 1000);
});
}
// Verwenden
fetchUser(1)
.then(user => console.log("User:", user))
.catch(error => console.error("Fehler:", error));🌐 Beispiel 2: Verkettete API-Aufrufe
javascript
function fetchUser(id) {
return new Promise(resolve => {
setTimeout(() => resolve({ id, name: "Max" }), 500);
});
}
function fetchPosts(userId) {
return new Promise(resolve => {
setTimeout(() => resolve([{ title: "Post 1" }, { title: "Post 2" }]), 500);
});
}
// Verkettung
fetchUser(1)
.then(user => {
console.log("User:", user);
return fetchPosts(user.id);
})
.then(posts => {
console.log("Posts:", posts);
})
.catch(error => console.error(error));🌐 Beispiel 3: Parallele API-Aufrufe
javascript
function fetchUser() {
return new Promise(resolve => {
setTimeout(() => resolve({ name: "Max" }), 1000);
});
}
function fetchPosts() {
return new Promise(resolve => {
setTimeout(() => resolve([{ title: "Post 1" }]), 800);
});
}
function fetchComments() {
return new Promise(resolve => {
setTimeout(() => resolve([{ text: "Kommentar 1" }]), 1200);
});
}
// Alle parallel ausführen
Promise.all([fetchUser(), fetchPosts(), fetchComments()])
.then(([user, posts, comments]) => {
console.log("User:", user);
console.log("Posts:", posts);
console.log("Comments:", comments);
})
.catch(error => console.error(error));11.7 Asynchroner Ablauf - Elegante Schreibweise
🎯 Callback Hell vs Promise
javascript
// ❌ Callback Hell
function getUser(callback) {
setTimeout(() => {
callback({ name: "Max" });
}, 500);
}
function getPosts(user, callback) {
setTimeout(() => {
callback([{ title: "Post 1" }]);
}, 500);
}
getUser((user) => {
getPosts(user, (posts) => {
console.log(user, posts);
});
});
// ✅ Promise (eleganter)
function getUser() {
return new Promise(resolve => {
setTimeout(() => resolve({ name: "Max" }), 500);
});
}
function getPosts(user) {
return new Promise(resolve => {
setTimeout(() => resolve([{ title: "Post 1" }]), 500);
});
}
getUser()
.then(user => {
console.log(user);
return getPosts(user);
})
.then(posts => console.log(posts))
.catch(error => console.error(error));Vorteile von Promise:
- ✅ Bessere Lesbarkeit
- ✅ Einfachere Fehlerbehandlung
- ✅ Verkettung (Chaining) möglich
- ✅ Parallele Ausführung mit
Promise.all()
🎉 Zusammenfassung
In diesem Kapitel hast du gelernt:
- ✅ Was Callback Hell ist und warum es schlecht ist
- ✅ Promise Grundlagen (Pending, Fulfilled, Rejected)
- ✅
then(),catch(),finally() - ✅
Promise.all()für parallele Anfragen - ✅
Promise.race()für Wettbewerb-Szenarien - ✅ Praxisanwendungen (API-Anfragen simulieren)
📝 Übung
Promise erstellen:
javascript// Erstelle ein Promise, das nach 1 Sekunde "Hallo" zurückgibtVerkettung:
javascript// Verketet zwei Promises: // 1. Zahl verdoppeln // 2. Ergebnis verdreifachenPromise.all():
javascript// Erstelle 3 Promises und führe sie parallel aus
➡️ Nächstes Kapitel
In Kapitel 12 lernen wir async/await - die modernste und eleganteste Art, asynchronen Code zu schreiben!
