# 🌐 JS 05: Callbacks, Event Loop & Promises Willkommen zu **Modul 05** des JavaScript-Kurses! In diesem Kapitel lernst du das HerzstĂŒck der modernen Web-Entwicklung kennen: **Asynchrone Programmierung mit Promises**. --- ## 📖 1. Synchron vs. Asynchron & Der Event Loop JavaScript fĂŒhrt Code in einer einzigen HauptausfĂŒhrungsschleife aus (**Single-Threaded**). - **Synchrone AusfĂŒhrung (Blockierend):** Jede Codezeile wird nacheinander ausgefĂŒhrt. Dauert eine Operation lange (z. B. ein schwerer Rechenschritt oder ein synchrones Warten), friert das gesamte Programm (und die Webseite!) ein. - **Asynchrone AusfĂŒhrung (Nicht-blockierend):** Zeitintensive Aufgaben (z. B. Netzwerk-Anfragen, Timer oder Dateizugriffe) werden im Hintergrund angestoßen. JavaScript lĂ€uft wĂ€hrenddessen sofort weiter. Sobald das Ergebnis vorliegt, wird ein Callback in die Warteschlange gelegt und vom **Event Loop** abgearbeitet. ```javascript console.log("1. Bestellung aufgeben"); setTimeout(() => { console.log("3. Essen ist fertig!"); // Asynchroner Callback nach 1000ms }, 1000); console.log("2. An den Tisch setzen und plaudern"); // Ausgabe-Reihenfolge: 1 -> 2 -> 3 ``` --- ## 🍔 2. Die Restaurant-Pieper-Analogie Stell dir vor, du bestellst Burger in einem Selbstbedienungs-Restaurant: 1. **Bestellung:** Du gehst an die Kasse und bestellst dein MenĂŒ. 2. **Der Pieper (`Promise` im Zustand `pending`):** Die Bedienung gibt dir sofort einen elektronischen Pieper in die Hand. Du musst *nicht* stur am Tresen stehen bleiben und die Schlange blockieren. 3. **Nicht-blockierendes Warten:** Du setzt dich an deinen Tisch, surfst am Smartphone oder unterhĂ€ltst dich mit Freunden (JavaScript Event Loop verarbeitet andere Ereignisse). 4. **Erfolg (`resolve` -> `fulfilled`):** Der Pieper vibriert und leuchtet grĂŒn! Du holst dein frisches Essen ab (`.then(essen => ...)`). 5. **Fehler (`reject` -> `rejected`):** Der Pieper piept rot und die Bedienung ruft: *"Die Burger-Patties sind leider aus!"* (`.catch(fehler => ...)`). --- ## ⏳ 3. Was ist ein Promise? Ein **Promise** (deutsch: *Versprechen*) ist ein Objekt, das einen Wert reprĂ€sentiert, der jetzt, in der Zukunft oder nie verfĂŒgbar ist. ### Die 3 ZustĂ€nde eines Promise: ``` ┌───> fulfilled (erfolgreich gelöst) ──> .then(wert) pending ─────── (schwebend) └───> rejected (fehlgeschlagen) ──> .catch(fehler) ``` 1. **`pending` (schwebend):** Die asynchrone Operation lĂ€uft noch. Weder Erfolg noch Fehler. 2. **`fulfilled` (erfĂŒllt):** Die Operation war erfolgreich, `resolve(wert)` wurde aufgerufen. 3. **`rejected` (abgewiesen):** Ein Fehler ist aufgetreten, `reject(error)` wurde aufgerufen. --- ## đŸ› ïž 4. Eigene Promises erstellen Ein Promise wird mit dem Konstruktor `new Promise(executor)` erzeugt. Die Executor-Funktion erhĂ€lt zwei Parameter: `resolve` und `reject`. ```javascript function simuliereDatenAbruf(erfolgreich) { return new Promise((resolve, reject) => { setTimeout(() => { if (erfolgreich) { resolve({ id: 1, name: "Max Mustermann" }); } else { reject(new Error("Netzwerk-Timeout beim Laden!")); } }, 500); }); } ``` --- ## 🔗 5. Promise-Chaining: `.then()`, `.catch()`, `.finally()` Promises ermöglichen sauberes Verketten ohne verschachtelte Callback-Pyramiden (*Callback Hell*): ```javascript simuliereDatenAbruf(true) .then((daten) => { console.log("Erhaltene Daten:", daten.name); return daten.id; // RĂŒckgabewert wird als nĂ€chstes Promise weitergegeben }) .then((userId) => { console.log("Lade Details fĂŒr ID:", userId); }) .catch((err) => { console.error("Ein Fehler ist aufgetreten:", err.message); }) .finally(() => { console.log("Lade-Indikator ausblenden (wird immer ausgefĂŒhrt)"); }); ``` --- ## ⚡ 6. Parallele AusfĂŒhrung mit `Promise.all()` und `Promise.race()` ### `Promise.all([p1, p2, ...])` FĂŒhrt mehrere Promises parallel aus und wartet, bis **alle** erfolgreich aufgelöst wurden. - Gibt ein Array mit allen Einzelergebnissen `[res1, res2, ...]` zurĂŒck. - **Fail-Fast:** Bricht sofort ab, sobald *auch nur ein einzelnes* Promise rejected! ```javascript const p1 = fetchUser(); const p2 = fetchPosts(); Promise.all([p1, p2]) .then(([user, posts]) => { console.log("User & Posts gleichzeitig geladen:", user, posts); }) .catch(err => console.error("Mindestens eine Quelle schlug fehl:", err)); ``` ### `Promise.race([p1, p2, ...])` Liefert das Ergebnis des **allerschnellsten** Promise (egal ob `resolve` oder `reject`). Ideal z. B. fĂŒr Timeouts. --- ## 🎯 7. Deine Aufgaben in `aufgabe.js` 1. **`verzoegereAusfuehrung(ms, rueckgabeWert)`**: Erzeuge ein Promise, das nach `ms` Millisekunden mittels `setTimeout` den `rueckgabeWert` auflöst. 2. **`pruefeZahlGroesserNull(zahl)`**: PrĂŒfe die Zahl: Resolve bei `zahl > 0`, Reject mit `new Error("Zahl muss grĂ¶ĂŸer als 0 sein")` bei `<= 0`. 3. **`ladeBenutzerProfil(userId)`**: Asynchrones Profil-Laden: Resolve mit `{ id: userId, name: "Benutzer_" + userId, status: "aktiv" }` bei `userId > 0`, sonst Reject mit `new Error("UngĂŒltige User-ID")`. 4. **`ladeAlleDatenQuellen(quelleA, quelleB)`**: Nutze `Promise.all([quelleA, quelleB])`, um zwei asynchrone Datenströme parallel zu aggregieren.