EMZETT.
Login

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 ms

Selbst 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
fertig

Promises

Ein Promise ist ein Versprechen auf ein späteres Ergebnis. Es hat drei Zustände:

ZustandBedeutung
pendingläuft noch
fulfillederfolgreich, mit einem Wert
rejectedfehlgeschlagen, 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äumt
  • resolve(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' ]
MethodeErgebnis
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
Microtask

Promises 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
Timer

Callback-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: true

Merke

  • 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 auf
  • Promise.all, allSettled, race, any kombinieren 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

Weiter im Kurs

Zurück: Iteratoren und Generatoren

Weiter: async/await und fetch

Alle Kapitel: JavaScript im Überblick