Im Laufe meiner Zeit als Entwickler habe ich schon einiges an Code gesehen: kompliziert, merkwürdig, umständlich, WTF … bis hin zu genial, schön gelöst oder einfach nur WOW.
Nach und nach lernt jeder einige Herangehensweisen um Probleme besser oder einfacher zu lösen. Ein Kollege würde sagen “Das ist aber smart gelöst”. Meiner Meinung nach hat das nicht immer was mit smart zu tun, smart ist meistens nur eine gewaltige Portion Erfahrung. Ich meine auch nicht Erfahrung in Lebensjahren, sondern Erfahrung in Programmierung. Und auch nicht theoretische Erfahrung sonder praktische.
Schau dir fremden Code an, lerne daraus und schreibe selbst
Immer mal wieder werde ich mir nun einige misslungene Codezeilen schnappen, die ich in der freien Wildbahn so finde und dafür elegantere Lösungen zeigen.
Promises und try/catch
Das Beispiel zeigt die Verwendung von Promises und den Versuch in synchroner Vorgehensweise Fehler abzufangen. Promises sind von Natur aus auf Asynchronität ausgelegt. D.h. bis das Promise wirklich fertig ist, ist die Ausführung des return Statements wahrscheinlich schon lange erledigt.
Zusätzlich muss man folgendes wissen, wenn in der Methode `methodReturnPromise` nun wirklich asynchron gearbeitet wird (zum Beispiel mit Ajax) wird das catch niemals den Fehler abfangen.
Ich versuche das einmal sehr plastisch darzustellen, um zu veranschaulichen wieso das so ist.
Stelle dir einmal folgendes vor: Ein Hund möchte von einer Katze ein Versprechen. Die Katze sagt zum Hund: “Du, das dauert etwas, mach ruhig mal weiter mit deiner Arbeit”. Der Hund macht schön weiter und sagt nun zu einer Kuh: “Ich bin soweit fertig, hier hast du aber noch das Versprechen von der Katze, warte einfach noch auf Ihre Antwort”
Der Hund ist nun komplett aus dem Spiel, er kann sich noch so anstellen. Wenn die Katze nun zur Kuh sagt “Ohje, ich hab hier nen Fehler” dann kann der Hund hier nichts mehr machen. So ähnlich läuft das auch mit der Asynchronität. Das try/catch in unserem Beispiel hat keine Chance hier irgendwas abzufangen.
Wir haben nun mehrere Möglichkeiten das ganze zu beheben oder schöner zu gestalten.
Wenn ich nun von dem obigen Beispiel direkt ausgehe, wäre das sinnvollste, direkt das Promise als return Wert zu nutzen.
In diesem Fall wäre die Methode execute sogar überhaupt nicht notwendig und wir könnten direkt immer methodReturnPromise() nutzen. Lassen wir die Methode einmal so stehen und geben das Promise so zurück. Wieso es besser ist, direkt das Promise zurückzugeben ist recht einfach. Promises bieten selbst eine Möglichkeit, Fehler weiterzureichen oder mit Fehlern zu arbeiten bzw. sie abzufangen.
Wenn in einem Promise ein Fehler passiert, kann dieses Promise abgewiesen (rejected) werden. Das Versprechen wird also nicht eingelöst, es wird abgewiesen. Dazu aber später.
Möchten wir nun trotzdem in unserer Execute-Funktion einen Fehler von methodReturnPromise abfangen, gehen wir hier wie folgt vor:
Unsere Execute-Methode besitzt nun keinen Return-Wert mehr, weil das meiner Meinung nach keinen Sinn ergibt, wenn darin schon der Fehler abgefangen wird. Es würde jetzt nur Sinn ergeben, wenn im catch Teil eine Art Fallback ausgeführt würde.
Eine bessere Vorgehensweise ist, Fehler schnell zustande kommen zu lassen. Hier ist nicht gemeint, dass du mutwillig Fehler in den Code einbauen sollst, sondern in deinen Methoden Vorgehensweisen umsetzt, die vor Ausführungen bestimmte Gegebenheiten prüfen und schnell Fehler werfen. Hier bieten sich sogenannte Wächter-Abfragen an.
Ein Beispiel für unsere execute Methode mit return wäre:
Das ganze mit Fallback könnte so aussehen:
Wenn nun jemand unsere execute() Methode nutzt, kann dieser schön auf die Promises reagieren.
Meine priorisierte Vorgehensweise ist
Einmal ist diese Methode einfach zu lesen, fängt erste Ungereimtheiten ab und gibt jedesmal ein Promise zurück.
Ich hoffe, es hat ein wenig Klarheit gebracht und gab neue Denkansätz in Sachen Promises und Fehler. Demnächst erkläre ich, wie in Promises selbst Fehler geworfen werden können und wie mit diesen umgegangen werden kann.