W3docs

JavaScript Promises

JavaScript Promises erklärt: pending, fulfilled und rejected, die Executor-Funktion mit resolve und reject, then/catch/finally und Microtask-Timing, mit ausführbaren Beispielen.

Promises in JavaScript sind ein leistungsstarkes Werkzeug zur Verwaltung asynchroner Operationen und ermöglichen es Entwicklern, saubereren und robusteren Code zu schreiben. Dieses Kapitel erklärt, was ein Promise ist, welche drei Zustände es annehmen kann, wie die Executor-Funktion mit resolve und reject funktioniert, wie man Ergebnisse mit .then, .catch und .finally verarbeitet und wann Promise-Callbacks tatsächlich ausgeführt werden (die Microtask-Warteschlange). Das Verständnis dieser Grundlagen ist unverzichtbar, bevor man zu Chaining, der Promise API und async/await übergeht.

Einführung in JavaScript Promises

Ein Promise ist ein object, das einen Wert repräsentiert, der möglicherweise noch nicht verfügbar ist, aber es zu einem späteren Zeitpunkt sein wird. Anstatt einen Callback in eine asynchrone Funktion zu übergeben und zu hoffen, dass er aufgerufen wird, erhält man sofort ein Promise-object und hängt Callbacks daran. Das vermeidet tief verschachtelte Callbacks, oft als „Callback Hell" bezeichnet, und bietet eine einheitliche, konsistente Methode zur Behandlung von Erfolg und Fehlschlag.

Eine typische asynchrone Aufgabe — eine Netzwerkanfrage, ein Timer, das Lesen einer Datei — hat ihr Ergebnis nicht sofort bereit. Das Promise ist ein Platzhalter für dieses Ergebnis.

Die drei Zustände eines Promise

Ein Promise befindet sich immer in genau einem von drei Zuständen:

  • pending — der Anfangszustand; die Operation wurde noch nicht abgeschlossen.
  • fulfilled — die Operation wurde erfolgreich abgeschlossen und das Promise hat einen Wert.
  • rejected — die Operation ist fehlgeschlagen und das Promise hat einen Grund (normalerweise ein Error).

Ein pending Promise kann in den Zustand fulfilled oder rejected übergehen. Sobald dies geschehen ist, ist es settled und kann seinen Zustand nicht mehr ändern. Dieser einseitige, einmalige Übergang macht Promises vorhersehbar: Ein .then-Callback, der an ein bereits erfülltes Promise angehängt wird, wird trotzdem ausgeführt, und ein Promise kann nie von fulfilled zurück zu rejected wechseln.

                  ┌─────────────┐  resolve(value)   ┌─────────────┐
                  │   pending   │ ────────────────▶ │  fulfilled  │
   new Promise ─▶ │             │                   └─────────────┘
                  │             │  reject(reason)   ┌─────────────┐
                  └─────────────┘ ────────────────▶ │  rejected   │
                                                    └─────────────┘

Ein Promise erstellen

Um ein Promise zu erstellen, ruft man den Promise-Konstruktor auf und übergibt ihm eine Funktion, die als Executor bezeichnet wird. Der Executor läuft sofort und synchron, sobald das Promise erstellt wird. Er erhält zwei Funktionen als Argumente, die üblicherweise resolve und reject genannt werden:

  • Rufe resolve(value) auf, um das Promise mit value zu erfüllen.
  • Rufe reject(reason) auf, um das Promise mit reason abzulehnen.

Solange keiner von beiden aufgerufen wird, bleibt das Promise pending.


javascript— editable

Der Executor erhält resolve und reject, damit er das Promise abschließen kann, sobald die asynchrone Arbeit beendet ist. Hier wird das Promise nach einem einsekundigen Timer erfüllt:


javascript— editable

Hinweis: Nur der erste Aufruf von resolve oder reject ist relevant. Sobald ein Promise settled ist, werden alle weiteren Aufrufe von resolve oder reject ignoriert. Wenn der Executor synchron einen Fehler wirft, wird das Promise automatisch mit diesem Fehler abgelehnt.

Ergebnisse verarbeiten mit .then, .catch und .finally

Sobald ein Promise erstellt wurde, verarbeitet man sein Ergebnis mit den Methoden .then, .catch und .finally. So reagiert der Rest des Codes auf ein settled Promise.

Die Methode then

Die Methode .then wird verwendet, um einen Callback zu planen, der ausgeführt wird, wenn das Promise erfüllt wird. Damit ein Promise erfüllt wird, muss die resolve-Methode aufgerufen werden. Das Argument, das man an resolve übergibt, wird der endgültige Wert des Promise.


javascript— editable

In diesem Code wird das Promise erst nach dem 1000-ms-Timeout erfüllt, wenn die resolve-Methode mit „Done!" aufgerufen wird.

Die Funktion im then-Teil wird nur ausgeführt, nachdem die resolve-Methode aufgerufen wurde.

.then kann auch ein zweites Argument annehmen — einen Ablehnungs-Handler — aber die Verwendung eines separaten .catch (weiter unten) ist übersichtlicher und fängt auch Fehler aus früheren Handlern ab.

Die Methode .catch

Die Methode .catch wird verwendet, um das Promise zu behandeln, falls es abgelehnt wird. Das bedeutet, dass entweder ein Fehler im Promise-Funktionsblock geworfen wird oder die reject-Methode aufgerufen wird.


javascript— editable

Für umfangreichere Fehlerbehandlungsmuster — Ablehnung gegenüber geworfenen Fehlern, erneutes Werfen und Wiederherstellen innerhalb einer Kette — siehe Fehlerbehandlung mit Promises.

Die Methode .finally

Die Methode .finally ermöglicht es, Code auszuführen, nachdem das Promise settled ist, unabhängig von seinem Ergebnis. Sie erhält keine Argumente (sie weiß nicht, ob das Promise erfüllt oder abgelehnt wurde) und gibt das Ergebnis oder den Fehler unverändert weiter — sie ist daher ideal für Aufräumarbeiten wie das Ausblenden eines Lade-Spinners.


javascript— editable

Wann werden Promise-Callbacks ausgeführt? (Microtasks)

Eine häufige Überraschung ist, dass .then-, .catch- und .finally-Callbacks niemals synchron ausgeführt werden, selbst wenn das Promise bereits settled ist. Sie werden in die Microtask-Warteschlange eingereiht, die die Engine erst verarbeitet, nachdem der aktuelle synchrone Code abgeschlossen ist.

Das bedeutet, dass synchroner Code immer zuerst ausgeführt wird und Promise-Callbacks vor Timern (setTimeout) laufen, die sich in der separaten Macrotask-Warteschlange befinden.


javascript— editable

Obwohl das Promise sofort aufgelöst wird und das Timeout 0 beträgt, wird der Promise-Callback (3) vor dem Timeout-Callback (4) ausgeführt, weil die Microtask-Warteschlange vollständig geleert wird, bevor die nächste Macrotask ausgeführt wird.

Daten von einer API mit Promises abrufen

Dieses Beispiel zeigt, wie man mit Promises Daten von einer externen API abruft.


javascript— editable

Promises verketten

Promise-Chaining ist eine leistungsstarke Funktion, mit der man mehrere asynchrone Operationen miteinander verknüpfen kann. Jedes .then gibt ein neues Promise zurück, und was auch immer man aus einem Handler returnt, wird zum Erfüllungswert dieses neuen Promise — deshalb trägt das folgende Beispiel einen Wert durch mehrere Schritte. Weitere Informationen finden sich unter JavaScript: Promises und Chaining.


javascript— editable

async/await mit JavaScript Promises kombinieren

Die effektive Verwendung von async/await kann die Handhabung asynchroner Operationen vereinfachen und den Code übersichtlicher und leichter verständlich machen, während die volle Leistungsfähigkeit von JavaScript Promises erhalten bleibt. Mehr darüber erfährt man unter JavaScript async/await, aber hier ist ein einfaches Beispiel.


javascript— editable

Fazit

Die Beherrschung von JavaScript Promises ist für jeden Entwickler entscheidend, der asynchrone Operationen effizient verwalten möchte. Das grundlegende Modell sollte man im Gedächtnis behalten: Ein Promise ist pending, bis der Executor resolve oder reject aufruft; danach ist es settled für immer; das Ergebnis liest man mit .then/.catch/.finally; und diese Callbacks werden immer als Microtasks ausgeführt, nach dem aktuellen synchronen Code.

Wie geht es weiter?

Übung

Übung
Was ist ein Promise in JavaScript?
Was ist ein Promise in JavaScript?
Was this page helpful?