W3docs

JavaScript async/await

JavaScript async/await: async-Funktionen, await, Fehlerbehandlung mit try/catch, sequenziell vs. parallel mit Promise.all, Top-Level-await und häufige Fallstricke.

Die async/await-Syntax ist der moderne, gut lesbare Weg, um asynchronen Code in JavaScript zu schreiben. Sie baut direkt auf Promises auf — async/await ersetzt sie nicht, sondern bietet eine sauberere Syntax zum Verwenden von Promises. Anstatt .then()-Callbacks zu verketten, schreibt man Code, der von oben nach unten wie normaler synchroner Code aussieht, während die Engine das Warten im Hintergrund übernimmt.

Dieses Kapitel behandelt, was async-Funktionen zurückgeben, wie await die Ausführung pausiert, Fehlerbehandlung mit try...catch, sequenzielle versus parallele Ausführung von Aufgaben, Top-Level-await in Modulen sowie die häufigsten Fallstricke.

async-Funktionen geben immer ein Promise zurück

Eine Funktion mit async zu markieren hat zwei Auswirkungen: Es erlaubt die Verwendung von await innerhalb des Funktionskörpers, und es garantiert, dass die Funktion ein Promise zurückgibt. Jeder return-Wert wird zum aufgelösten Wert dieses Promise; ein throw lässt das Promise ablehnen.

javascript— editable

Da der Rückgabewert ein Promise ist, muss der Aufrufer weiterhin await (oder .then()) verwenden, um den eigentlichen Wert zu lesen. Ein typischer Anfängerfehler ist die Erwartung, dass greet() direkt 'Hello' zurückgibt.

await pausiert bis das Promise abgeschlossen ist

Der await-Operator kann nur innerhalb einer async-Funktion verwendet werden (oder auf der obersten Ebene eines Moduls — siehe unten). Er pausiert die Funktion, bis das Promise rechts von ihm abgeschlossen ist: Bei Erfolg gibt er den aufgelösten Wert zurück, bei Ablehnung wirft er den Ablehnungsgrund als Ausnahme.

Entscheidend ist: await blockiert nicht das gesamte Programm. Es unterbricht nur die aktuelle async-Funktion; der restliche Code und der Event-Loop laufen weiter.

javascript— editable

Man kann jeden Wert awaiten, nicht nur ein Promise. Nicht-Promise-Werte werden umhüllt und sofort aufgelöst, sodass await 5 schlicht 5 ergibt.

Fehlerbehandlung mit try...catch

Einer der größten Vorteile von async/await ist, dass Fehler mit demselben try...catch behandelt werden, das man auch für synchronen Code verwendet. Ein abgelehntes Promise wird an der await-Stelle zu einer geworfenen Ausnahme, die catch abfangen kann.

javascript— editable

Wird eine Ablehnung nicht abgefangen, entsteht eine unhandled promise rejection. Einen tieferen Einblick in die Promise-Mechanismen bietet Fehlerbehandlung mit Promises.

Ein praxisnahes Beispiel: Daten abrufen und Fehler sauber melden.

javascript— editable

Beachte die explizite Prüfung response.ok: fetch lehnt nur bei Netzwerkfehlern ab, nicht bei HTTP-Fehlerstatus wie 404 oder 500 — daher muss man die Antwort selbst prüfen.

Sequenzielle vs. parallele Ausführung

Hier wird await am häufigsten falsch eingesetzt. Wenn man Operationen nacheinander awaitet, laufen sie sequenziell — jede wartet auf den Abschluss der vorherigen. Das ist nur dann richtig, wenn eine spätere Aufgabe von einem früheren Ergebnis abhängt.

Sequenziell (wenn Aufgaben voneinander abhängen)

async function pipeline() {
  const user = await getUser(1);          // step 1
  const posts = await getPosts(user.id);  // needs user.id, so must wait
  return posts;
}

Parallel (wenn Aufgaben unabhängig sind)

Wenn die Aufgaben nicht voneinander abhängen, verschwendet man Zeit, wenn man sie nacheinander abwartet. Starte alle gleichzeitig und warte gemeinsam mit Promise.all:

javascript— editable

Promise.all lehnt ab, sobald eines seiner Promises abgelehnt wird. Wenn stattdessen auf jedes Promise unabhängig von Erfolg oder Misserfolg gewartet werden soll, verwende Promise.allSettled. Die vollständige Familie der Kombinatoren ist in der Promise-API beschrieben.

Top-Level-await in Modulen

Innerhalb von ES-Modulen (<script type="module"> oder .mjs-Dateien) kann await auf der obersten Ebene ohne Einbettung in eine async-Funktion verwendet werden:

// data.mjs — an ES module
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const todo = await response.json();

export { todo };

Das ist praktisch für die Modulinitialisierung, etwa um Konfigurationen zu laden, bevor die Exporte des Moduls bereitstehen. Ein Modul, das Top-Level-await verwendet, verzögert die Auswertung jedes Moduls, das es importiert. Top-Level-await funktioniert nur in Modulen — in einem klassischen Script oder einer normalen Funktion ist es ein Syntaxfehler.

Häufige Fallstricke

await nicht in einer Schleife für unabhängige Aufgaben verwenden

Die Verwendung von await in einer for-Schleife zwingt die Iterationen, eine nach der anderen zu laufen. Wenn die Iterationen unabhängig sind, ist das unnötig langsam.

javascript— editable

await in einer Schleife sollte nur dann eingesetzt werden, wenn jede Iteration tatsächlich von der vorherigen abhängt oder Anfragen gedrosselt werden müssen.

Weitere Fallstricke

  • forEach ignoriert async-Callbacks. array.forEach(async ...) wartet nicht auf die Promises. Stattdessen sollte eine for...of-Schleife oder Promise.all(array.map(...)) verwendet werden.
  • await nicht vergessen. Eine async-Funktion ohne await (oder .then()) aufzurufen gibt ein austehendes Promise zurück und verschluckt Fehler lautlos. Linter weisen oft auf solche „schwebenden" Promises hin.
  • fetch lehnt bei HTTP-Fehlern nicht ab. Immer response.ok prüfen, wie oben gezeigt.

Fazit

async/await lässt asynchronen JavaScript-Code wie synchronen Code aussehen und hält gleichzeitig den Event-Loop frei. Die wichtigsten Punkte: Jede async-Funktion gibt ein Promise zurück, await pausiert nur die aktuelle Funktion, Fehler fließen durch try...catch, und unabhängige Aufgaben sollten parallel mit Promise.all ausgeführt werden, anstatt sie einzeln nacheinander abzuwarten. Um das Fundament dieser Syntax zu festigen, empfiehlt sich die Lektüre von Promises und Promise-Chaining.

Übungen

Übung
Welche Funktion hat das Schlüsselwort 'async' in JavaScript?
Welche Funktion hat das Schlüsselwort 'async' in JavaScript?
Was this page helpful?