W3docs

JavaScript Promise Chaining

Promise Chaining in JavaScript ermöglicht die sequenzielle Ausführung asynchroner Operationen – lesbar, wartbar und mit zentraler Fehlerbehandlung.

Promise Chaining ermöglicht es, asynchrone Operationen nacheinander auszuführen, wobei jeder Schritt erst beginnt, wenn der vorherige abgeschlossen ist. Dazu hängt man eine Folge von .then()-Handlern an ein Promise an, und jeder Handler empfängt das Ergebnis des vorangegangenen Schritts.

Vor Promises bedeutete die Sequenzierung asynchroner Aufgaben das Verschachteln von Callbacks in Callbacks — das berüchtigte „Callback Hell" oder „Pyramid of Doom":

queryDatabase('users', (users) => {
  queryDatabase('posts', (posts) => {
    queryDatabase('comments', (comments) => {
      // deeply nested, hard to read, error handling duplicated everywhere
    });
  });
});

Chaining macht diese Pyramide flach und erzeugt eine lesbare, von oben nach unten verlaufende Sequenz mit einem einzigen Ort für die Fehlerbehandlung. Diese Seite erklärt, wie Chaining tatsächlich funktioniert, den häufigsten Fehler (ein fehlendes return), Fehlerbehebung und Aufräumen. Für die verwandte Syntax, die auf Promises aufbaut, siehe JavaScript: async/await.

Wie Chaining funktioniert: Jedes .then() gibt ein neues Promise zurück

Das ist die grundlegende Mechanik, aus der alles andere folgt. .then() gibt nicht das ursprüngliche Promise zurück — es gibt ein brandneues Promise zurück. Worauf dieses neue Promise aufgelöst wird, hängt davon ab, was der Handler zurückgibt:

  • Einen einfachen Wert zurückgeben → das nächste .then() empfängt diesen Wert.
  • Ein Promise zurückgeben → die Kette wartet, bis es abgeschlossen ist, und das nächste .then() empfängt seinen aufgelösten Wert (nicht das Promise selbst).
  • Nichts zurückgeben → das nächste .then() empfängt undefined.
  • Einen Fehler werfen → die Kette überspringt alles bis zum nächsten .catch().

Da jedes .then() ein neues Promise zurückgibt, kann man weitere .then()-Aufrufe anhängen und einen Wert durch die Kette weitergeben:

javascript— editable

Der mächtige Fall ist die Rückgabe eines Promise aus einem Handler. Die Kette pausiert, bis dieses Promise aufgelöst wird, bevor sie fortfährt — genau so sequenziert man abhängige asynchrone Operationen:

Grundlegendes Promise Chaining

Stellen Sie sich das Szenario vor, in dem Sie eine Datenbank abfragen müssen und dann das Ergebnis dieser Abfrage für eine weitere Abfrage verwenden. Jedes .then() gibt das Promise der nächsten Abfrage zurück, sodass die Kette wartet, bis eine Abfrage abgeschlossen ist, bevor die nächste beginnt:

javascript— editable

Fehler Nr. 1: return vergessen (die „abgetrennte Kette")

Das ist der mit Abstand häufigste Fehler beim Promise Chaining. Wenn man eine asynchrone Operation innerhalb eines .then() startet, aber das Zurückgeben ihres Promise vergisst, wartet die Kette nicht darauf — das Ergebnis geht verloren, und das nächste .then() wird sofort mit undefined ausgeführt. Das innere Promise wird zu einer „abgetrennten" Kette, die eigenständig läuft.

In der fehlerhaften Version unten wird queryDatabase('posts') aufgerufen, aber sein Promise wird nicht zurückgegeben, sodass das zweite .then() undefined statt der Posts protokolliert:

javascript— editable

Das Hinzufügen von return stellt die Kette wieder her. Jetzt wartet das zweite .then() auf die Posts-Abfrage und empfängt deren Ergebnis:

javascript— editable

Tipp: Pfeilfunktionen mit einem Ausdrucks-Body geben automatisch zurück — .then(r => queryDatabase(r)) gibt das Promise zurück, aber .then(r => { queryDatabase(r); }) (mit geschweiften Klammern) tut das nicht.

Fehlerbehandlung in Ketten

Ein einzelnes .catch() am Ende der Kette behandelt jeden geworfenen Fehler — oder jedes abgelehnte Promise — an jedem früheren Schritt. Wenn etwas fehlschlägt, überspringt die Kette alle verbleibenden .then()-Aufrufe und springt direkt zum nächsten .catch().

In diesem Beispiel lehnt die erste Abfrage ab, sodass das .then() vollständig übersprungen wird und die Kontrolle bei .catch() landet:

javascript— editable

Für einen tieferen Einblick in Ablehnungsmuster, siehe Fehlerbehandlung mit Promises.

Mittiges .catch() zur Wiederherstellung

Ein .catch() muss nicht das letzte Glied sein. Mitten in einer Kette platziert, kann es einen Fehler behandeln, einen Fallback-Wert zurückgeben und die Kette fortführen. Das ist der Unterschied zwischen der Wiederherstellung nach einem Fehler und dem Abbruch der gesamten Sequenz.

Unten schlägt der erste Schritt fehl, aber ein mittiges .catch() liefert einen Standardwert und die Kette läuft weiter:

javascript— editable

Ein mittiges .catch() stellt wieder her und setzt fort; ein abschließendes .catch() ist das letzte Sicherheitsnetz für alles, was zuvor nicht wiederhergestellt wurde.

Aufräumen mit .finally()

.finally() wird ausgeführt, sobald das Promise abgeschlossen ist — egal ob es aufgelöst oder abgelehnt wurde. Es empfängt kein Argument und ändert den durch die Kette fließenden Wert nicht, was es ideal für Aufräumarbeiten macht, die in jedem Fall stattfinden müssen: einen Spinner ausblenden, eine Verbindung schließen oder einen Button wieder aktivieren.

javascript— editable

Promises parallel ausführen: Promise.all

Promise.all ist kein Chaining — Chaining ist sequenziell (eines nach dem anderen), während Promise.all Promises parallel ausführt und auf alle wartet. Verwenden Sie es, wenn die Operationen nicht voneinander abhängen und es keinen Grund gibt, auf eine zu warten, bevor die nächste beginnt.

Es nimmt ein iterierbares Objekt von Promises und gibt ein einzelnes Promise zurück, das zu einem Array ihrer Ergebnisse in derselben Reihenfolge wie die Eingabe aufgelöst wird. Jeder Nicht-Promise-Wert im Array (wie 42 unten) wird automatisch in ein aufgelöstes Promise eingehüllt. Wenn irgendeine Eingabe abgelehnt wird, lehnt das gesamte Promise.all sofort mit diesem Fehler ab.

javascript— editable

Für Promise.all, Promise.race, Promise.allSettled und die anderen Kombinatoren, siehe die Promise API.

Zusammenfassung

  • Jedes .then() gibt ein neues Promise zurück; die Kette liest sich von oben nach unten statt verschachtelt zu sein.
  • Werte zurückgeben, um sie weiterzugeben, und ein Promise aus einem Handler zurückgeben, damit die Kette darauf wartet.
  • Der häufigste Fehler ist ein fehlendes return innerhalb von .then() — es trennt die innere asynchrone Arbeit ab und der nächste Schritt erhält undefined.
  • Ein abschließendes .catch() behandelt Fehler von jedem früheren Schritt; ein mittiges .catch() kann wiederherstellen und fortsetzen.
  • Verwenden Sie .finally() für Aufräumarbeiten, die unabhängig vom Erfolg oder Misserfolg der Kette ausgeführt werden müssen.
  • Verwenden Sie Promise.all für unabhängige Aufgaben, die parallel ausgeführt werden sollen — das ist ein anderes Werkzeug als sequenzielles Chaining.
  • Wenn Sie sich hier sicher fühlen, bietet async/await dasselbe Verhalten mit synchron aussehendem Code.

Übungen

Übung
Was ist der Zweck von Promise Chaining in JavaScript?
Was ist der Zweck von Promise Chaining in JavaScript?
Was this page helpful?