Newsletter            Wir rufen zurück            Impressum

JavaScript Promises (Theorie)

Wenn es um JS promises geht, sind sich alle Blogs in einem Punkt einig: die anderen haben es falsch verstanden. In diesem Artikel werden wir auf die Eigenschaften der Promises eingehen, während wir die akademischen Diskussionen außen vor lassen.

Was ist ein Promise ?

Eine der Definitionen eines Promise lautet: „Ein Promise ist ein Objekt, das einen zukünftigen Wert greifbar macht.“ Dadurch erlaubt es uns, das Programm fortzusetzen, während wir auf die Antwort eines asynchronen Aufrufs warten.
Der Formalismus ist wie folgt gestaltet:

Abhängig davon ob man schon eine Antwort auf den im Promise enthaltenen asynchronen Aufruf erhalten hat, kann das Promise 3 Zustände annehmen:

  • pending: Es wurde noch keine Antwort erhalten
  • resolved: Es wurde eine Antwort erhalten und die Ausführung wird in der successCallback-Funktion fortgesetzt.
  • rejected: Es wurde eine Antwort erhalten und die Ausführung wird in der errorCallback-Funktion fortgesetzt.

Verkettung

Es ist möglich mehrere Promises mittels des Keywords ‚then‘ zu verketten:

Um die gleiche Funktionalität mittels einer Kette von Callbacks zu gestalten, müsste man sie schachteln, was bei einer steigenden Anzahl von Aufrufen zu einem sog. ‚callback hell‘ führt: ein Pyramidenförmiges, unübersichtliches Coding.

Um diese Verkettung zu ermöglichen, gibt jede ‚then‘-Funktion ein Promise zurück. Dies führt jedoch im Umkehrschluss dazu, dass auch die letzte ‚.then()‘-Funktion in der Kette ein Promise erstellt, welches jedoch keine ‚.then‘-Funktion erhält, welche auf sein Ergebnis reagieren würde. D.h. selbst wenn wir mittels des Befehls ‚resolve( )‘ das Promise in den ‚resolved‘-Zweig lenken würden, wäre dort kein Coding vorhanden.

Zurückweisung

Was passiert im obigen Beispiel, wenn eine der asynchronen Funktionen durch einen Fehler abbricht? Die ‚then‘-Funktion wird in den ‚rejected‘-Zweig gelenkt. Jedoch wurde in keiner dieser Funktionen der zweite Operand mit einer Funktion versehen, die den Fehler-Zweig behandelt. In diesem Fall wird der ‚rejected‘-Zustand an die nächste ‚.then()‘-Funktion weitergereicht, solange bis ein ‚rejected‘-Zweig vorhanden ist, oder bis die Kette der Promises abbricht. D.h. dass im oberen Fall bei einem Fehler in einem der asynchronen Aufrufe kein Effekt festzustellen ist, bis auf das Übergehen der folgenden ‚resolved‘-Zweige. Um einen Fehler zu registrieren ist folgendes Coding denkbar:

In diesem Fall wird die Ausführung des Programms nach einem Fehler in einer der asynchronen Funktionen in der ‚error‘-Funktion fortgesetzt. Natürlich könnte man in jeder ‚.then‘-Funktion einen eigenen ‚rejected‘-Zweig hineinprogrammieren, um auf die Fehler individuell zu reagieren. Der Grund warum die ‚error‘-Funktion im obigen Beispiel in einer separaten ‚then‘-Funktion definiert ist, liegt darin, dass Promises ihren Zustand nicht wechseln dürfen. Das heißt: wenn es zu einer Exception in der ‚process‘-Methode kommt, können wir das Promise nicht anweisen in den eigenen ‚rejected‘-Zweig zu springen, sondern brauchen dazu ein nachgeschaltetes Promise.

Zweig-unabhängiger Callback

Welche Variante ist nun zu wählen, wenn wir eine Code-Block nach der Auflösung des Promise ausführen wollen? Eine einfache Lösung wäre, das betreffende Coding auszulagern und die Funktion in beide Zweige des Promises zu kopieren. Jedoch bieten uns die Promises auch eine Funktionalität, die diesen Fall abdeckt: mit dem Befehl ‚finally‘ können wir ein Coding aufrufen, ungeachtet des Promise-Zweigs, in welchem wir zwischenzeitlich gelandet sind:

Zusammengefasst bietet das Promise-Konzept eine Möglichkeit mit asynchronen Funktionen umzugehen, welche einige Eigenschaften aufweist, die sie von anderen Ansätzen der Verarbeitung solcher Funktionen abhebt. In einem anderen Beitrag wird eine mögliche Anwendung von JavaScript Promises vorgestellt.

Antwort schreiben