Javascript Exceptions: try, catch (e), throw

try catch (e) throw testet einen Codeblock auf Fehler – nicht auf Syntaxfehler wie onerror, sondern auf Laufzeitfehler, und baut eine Umleitung ein, damit die Ausführung nach dem Fehler weitergeführt werden kann.

Damit try catch funktioniert, muss der Code frei von Syntaxfehlern sein.

Fehler entstehen durch fehlerhafte Anweisungen, durch fehlende oder falsche Eingaben oder unvorhergesehene Umstände und Ereignisse. Die meisten Fehler entstehen bei der Verarbeitung von Benutzereingaben und Daten von externen Ressourcen, denn das sind die unzuverlässigsten Quellen.

Im Internet sind unzählige Browsergenerationen mit ihren Browserbugs und unterschiedlichen Mankos unterwegs. Einige Fehler sind sofort sichtbar, andere können für Jahre unter der Oberfläche schmoren, bis sie eine unvorhergesehene Benutzeraktion eine fehlende Abfrage hervorholt.

Fehler gibt es immer wieder

Sobald ein Programm einen gewissen Grad an Komplexität erreicht, sind solche Situationen unvermeidlich. Sie müssen so gut wie möglich vorhergesehen und vorausschauend behandelt werden.

Programmiersprachen wie C oder C++ bieten schon lange Exceptions; Javascript hat seit Version 4.1 den try-catch()-Block mit dem »Werfen von Ausnahmen« Throw Exception. Jetzt sind wir also nicht mehr den Browsern ausgeliefert, die uns ihre Fehlermeldungen vor die Füße werfen und dann aussteigen, sondern können eine Umleitung einbauen.

Bei größeren Programmen überwiegt das Error Handling – die Behandlung von Fehlern und Ausnahmen – schnell die Logik des Programms. try … catch () … throw behandelt Fehler an zentraler Stelle und gestaltet den Code lesbarer.

try {}
testet einen Codeblock auf Fehler
catch {}
reagiert auf den Fehler und erledigt die Fehlerbehandlung
throw {}
erzeugt eigene Fehlermeldungen
finally {}
führt Anweisungen im Anschluss an try und catch aus, ob nun Fehler aufgetreten sind oder nicht und egal wie das Ergebnis aussah.

try catch: Exception-Handling

Exceptions (Ausnahmen) treten auf

  • wenn ein Fehler zur Laufzeit auftritt, z.B.
    • beim Aufruf einer undefinierten Variablen,
    • beim Aufruf einer Methode, die es gar nicht gibt (die der Browser nicht unterstützt),
    • bei einer falsche Benutzereingabe
  • wenn das Script selber eine Exception wirft – throws an exception.
<script>
try {
    console.log ("Anfang des Durchlaufs");
    cyrcelblock; // gibts nicht
    console.log ("Ende des Durchlaufs – wird nie erreicht");
} catch (e) {
    console.log ("Einen Fehler entdeckt " + e);
} finally {
    console.log ("Was immer ausgeführt wird");
}
console.log ("Und jetzt könnte die Ausführung weitergehen");
</script>

Die Methode cyrcelblock() gibt es nicht, die Anweisung nach cyrcelblock() wird nicht ausgeführt, sondern weiter geht es bei catch (e).

[Log] Anfang des Durchlaufs
[Log] Einen Fehler entdeckt  ReferenceError: Can't find variable: cyrcelblock 214:14
[Log] Was immer ausgeführt wird
[Log] Und jetzt könnte die Ausführung weitergehen

Der normale Code sitzt in den Klammern einer try-Anweisung. Die catch (e)-Anweisung bindet die Anweisungen ein, die im Fall einer Ausnahme ausgeführt werden.

Der Parameter e gibt den Fehler aus. Funktioniert auch ohne .stack, dann wird nur der Fehler ausgegeben (nicht alle Browser unterstützen den Fehlerstack).

Der Code im finally-Block wird immer ausgeführt, gleich, ob eine Exception – ein Fehler – auftrat oder nicht.

Trotz des Fehlers wird das Script an einer (hoffentlich) sicheren Stelle weiter ausgeführt.

throw

Browser haben viele Fehlermeldung fertig auf Lager, die aber nicht direkt die Fehlerquelle aufdecken. Scripte können ihre eigenen Exceptions mit der Anweisung throw werfen. Die Exception kann ein String, eine Zahl oder ein Objekt sein.

  • throw "Hier ist ein Fehler";
  • throw 12
  • throw new Error ("Hier ist ein Fehler")

Wenn wie hier im Beispiel die Anwendung auf dem Server einen Wert nicht zurückgibt, der erwartet wird:

let json = '{"price": 675}';
try {
    let product =  JSON.parse (json);
    if (!product.name) {
        throw new Error("Unvollständige Daten: Keine Produktnummer");
    }

    console.log ( product.name);
} catch (e) {
    console.log ("JSON : " + e);
}
JSON : Error: Unvollständige Daten: Keine Produktnummer

So kommt Javascript mit einer Fehlermeldung, die ausdrucksvoller ist als das übliche Reference Error des Browsers.

Muster von try catch throw

try {
  // Anweisungen, die zu Ausnahmen führen könnten 
}

catch ( exception1 ex ) {
  // Anweisungen, die diese Ausnahme behandlen
}

catch ( exception2 ex ) {
  // Anweisungen, die diese Ausnahme behandlen
}

catch ( exception3 ex ) {
  // Anweisungen, die diese Ausnahme behandlen
}
Mehre als ein catch in try catch throw

try-catch()-throw oder if-than-else

Für Fehler, auf die das Script vorbereitet ist, die wir voraussehen, die häufiger eintreten könnten und von denen sich ein Script erholen kann, wählt man i.d.R. eher einer if-than-else-Behandlung.

Mit if than else wird aber immer abgefragt, ob der Fehler nun auftritt oder nicht. Wenn der Fehler unter normalen Bedingungen nur selten auftritt, ist Exception-Handling effizienter, weil das Script unter normalen Bedingungen keine weiteren Prüfungen abhandelt.

Für gravierende Fehler, die eine Ausnahme darstellen, ist try catch () throw gedacht. Das schafft zwei Ebenen von Fehlermeldungen.

try {}catch (x) {catch (y) {catch (z) {}}}Exception aufgetretenErsten zutreffenden Block ausführenkein Block trifft zuKeine ExceptionaufgetretenFortfahren mit der ersten Anweisungnach dem letzten catch()Ausführung verlässtdie Methode