Fehlerursachen
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 alte 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.
Ein Klassiker: Der Zugriff mit querySelector auf ein Element, das es nicht gibt.
<script> let brd = document.querySelector(".brd") !== null; try { if (brd) { // Wird nie erreicht res.textContent = "wird gemacht"; } else { // Eine eigene Fehlermeldung erzeugen throw new Error ("Kein Element mit class brd gefunden"); } } catch (e) { // Fehler entdeckt console.log(e); } finally { console.log("Hier gehts auf jeden Fall weiter"); } </script>
[Log] Error: Kein Element mit class brd gefunden [Log] Hier gehts auf jeden Fall weiter
Das Element document.querySelector(".brd") gibt es nicht, aber es entsteht keine »natürliche« Fehlermeldung in der Konsole. Stattdessen erzeugt throw die eigene Ausnahme (Exeption): als String, Number, Boolean oder als Objekt.
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 }
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.