Kurz: JavaScript führt Code nacheinander in einem einzigen Ablauf aus. Aufgaben, die dauern (Netzwerk, Timer, Dateien), blockieren diesen Ablauf nicht.
Teil des Kurses JavaScript
Kapitel 25 von 40 im Kurs JavaScript (Abschnitt „Asynchroner Code“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.
JavaScript führt Code nacheinander in einem einzigen Ablauf aus. Aufgaben, die dauern (Netzwerk, Timer, Dateien), blockieren diesen Ablauf nicht: Du gibst an, was danach passieren soll, und das Programm macht in der Zwischenzeit weiter.
Timer und Callbacks
Ein Callback ist eine Funktion, die später aufgerufen wird:
console.log("1: Start");
setTimeout(() => console.log("3: nach 100 ms"), 100);
setTimeout(() => console.log("2b: nach 0 ms (trotzdem später!)"), 0);
console.log("2: Ende des Skripts");Ausgabe:
1: Start
2: Ende des Skripts
2b: nach 0 ms (trotzdem später!)
3: nach 100 msSelbst bei 0 ms läuft der Callback erst, nachdem der aktuelle Code fertig ist.
Callback-Hölle
Mehrere abhängige Schritte mit Callbacks werden schnell unleserlich:
function schritt(name, weiter) { setTimeout(() => { console.log(name); weiter(); }, 10); }
schritt("A", () => {
schritt("B", () => {
schritt("C", () => console.log("fertig"));
});
});Ausgabe:
A
B
C
fertigPromises
Ein Promise ist ein Versprechen auf ein späteres Ergebnis. Es hat drei Zustände:
| Zustand | Bedeutung |
|---|---|
| pending | läuft noch |
| fulfilled | erfolgreich, mit einem Wert |
| rejected | fehlgeschlagen, mit einem Fehler |
const warte = (ms, wert) => new Promise((resolve, reject) => {
setTimeout(() => {
if (wert === undefined) reject(new Error("kein Wert"));
else resolve(wert);
}, ms);
});
warte(50, "Hallo")
.then(w => { console.log("erhalten:", w); return w.toUpperCase(); })
.then(w => console.log("verkettet:", w))
.catch(e => console.log("Fehler:", e.message))
.finally(() => console.log("aufgeräumt"));
warte(10).catch(e => console.log("Fehler:", e.message));Ausgabe:
Fehler: kein Wert
erhalten: Hallo
verkettet: HALLO
aufgeräumtresolve(wert)meldet Erfolg,reject(fehler)meldet Misserfolg.then()verarbeitet das Ergebnis und liefert wieder ein Promise (daher verkettbar).catch()fängt Fehler aus allen Schritten davor.finally()läuft immer
Mehrere Promises kombinieren
const p = (ms, w) => new Promise(r => setTimeout(() => r(w), ms));
Promise.all([p(30, "a"), p(10, "b"), p(20, "c")])
.then(erg => console.log("all:", erg));
Promise.race([p(30, "langsam"), p(10, "schnell")])
.then(w => console.log("race:", w));
Promise.allSettled([p(5, 1), Promise.reject(new Error("x"))])
.then(erg => console.log("allSettled:", erg.map(e => e.status)));
Promise.any([Promise.reject(1), p(10, "klappt")])
.then(w => console.log("any:", w));Ausgabe:
allSettled: [ 'fulfilled', 'rejected' ]
race: schnell
any: klappt
all: [ 'a', 'b', 'c' ]| Methode | Ergebnis |
|---|---|
Promise.all([...]) | alle erfolgreich → Array; bricht beim ersten Fehler ab |
Promise.allSettled([...]) | wartet auf alle, egal ob Erfolg oder Fehler |
Promise.race([...]) | das erste fertige (Erfolg oder Fehler) |
Promise.any([...]) | das erste erfolgreiche |
Fertige Promises
Promise.resolve(42).then(console.log);
Promise.reject(new Error("nein")).catch(e => console.log(e.message));
queueMicrotask(() => console.log("Microtask"));
console.log("synchron zuerst");Ausgabe:
synchron zuerst
42
nein
MicrotaskPromises und die Reihenfolge
Promise-Callbacks laufen als Microtasks, noch vor Timer-Callbacks (Macrotasks), aber nach dem aktuellen Code:
setTimeout(() => console.log("Timer"), 0);
Promise.resolve().then(() => console.log("Promise"));
console.log("synchron");Ausgabe:
synchron
Promise
TimerCallback-APIs in Promises verpacken
const { promisify } = require("node:util");
const fs = require("node:fs");
// Alte Callback-Funktion in ein Promise verwandeln
const lesen = promisify(fs.readFile);
lesen(__filename, "utf8").then(t => console.log("gelesen:", t.length > 0));Ausgabe:
gelesen: trueMerke
- Lange Aufgaben blockieren nicht: Ergebnisse kommen später per Callback oder Promise
- Ein Promise ist pending, fulfilled oder rejected
.then()verkettet,.catch()fängt Fehler,.finally()räumt aufPromise.all,allSettled,race,anykombinieren mehrere Promises- Promise-Callbacks (Microtasks) laufen vor Timern
Übungsaufgabe
Baue eine Funktion warte(ms), die ein Promise zurückgibt, und führe drei Wartezeiten einmal nacheinander und einmal parallel mit Promise.all aus.
Quiz zur Selbstkontrolle
Was gibt .then() zurück?
- Ein neues Promise (richtig)
- Den Wert direkt
- undefined
- Ein Array
Was macht Promise.all?
- Wartet auf alle Promises und liefert die Ergebnisse als Array (richtig)
- Gibt das erste fertige zurück
- Bricht alle ab
- Führt sie nacheinander aus
Was läuft zuerst?
- Promise-Callbacks (Microtasks) vor setTimeout-Callbacks (richtig)
- setTimeout vor Promises
- Beides gleichzeitig
- Zufällige Reihenfolge
Weiter im Kurs
Zurück: Iteratoren und Generatoren
Weiter: async/await und fetch
Alle Kapitel: JavaScript im Überblick