JavaScript try…catch Fehlerbehandlung
JavaScript-Fehlerbehandlung mit try, catch, finally und throw. Error-Objekt, eingebaute Fehlertypen, optionales catch-Binding, Rethrowing und asynchrone Einschränkungen. Mit lauffähigen Beispielen.
Fehlerbehandlung in JavaScript mit Try...Catch meistern
Fehler effektiv zu behandeln ist entscheidend für die Entwicklung robuster Anwendungen in JavaScript. Wenn zur Laufzeit etwas schiefläuft — ein Netzwerkaufruf schlägt fehl, JSON ist fehlerhaft, eine Variable ist undefined — wirft JavaScript eine Exception. Ohne Behandlung stoppt diese Exception das Skript. Dieser Artikel behandelt die try...catch-Anweisung, die finally-Klausel, den throw-Operator, das Error-Objekt und seine eingebauten Untertypen, Rethrowing sowie die wichtige Einschränkung, dass synchrones try...catch keine Fehler abfangen kann, die innerhalb asynchroner Callbacks geworfen werden.
Try...Catch in JavaScript verstehen
Die try...catch-Anweisung ist ein Werkzeug zur Verwaltung von Exceptions — Fehlern, die während der Programmausführung auftreten. Sie ermöglicht es, diese Exceptions kontrolliert zu behandeln, anstatt das gesamte Skript abstürzen zu lassen.
Der Mechanismus besteht aus zwei Blöcken:
try— der Code, der möglicherweise einen Fehler wirft. JavaScript führt ihn normal aus.catch (error)— wird nur ausgeführt, wenn etwas imtry-Block eine Exception wirft. Der geworfene Wert wird alserrorübergeben.
Tritt kein Fehler auf, wird der catch-Block vollständig übersprungen. Tritt ein Fehler auf, springt die Ausführung sofort zu catch — der Rest des try-Blocks wird nicht ausgeführt.
Grundlegende Syntax von Try...Catch
Hier ist ein einfaches Beispiel, das die grundlegende Struktur von try...catch veranschaulicht:
In diesem Beispiel wird jeder Fehler, der im try-Block auftritt, vom catch-Block abgefangen, wo er behandelt werden kann, ohne dass das Skript abstürzt.
Eigene Fehler mit throw werfen
Der throw-Operator erzeugt eine Exception. Es kann jeder Wert geworfen werden, aber die Konvention — und das Einzige, was man in der Praxis tun sollte — ist, ein Error-Objekt (oder eine Instanz eines seiner Untertypen) zu werfen. Dadurch erhält man automatisch eine nützliche message und einen stack-Trace.
Vermeiden Sie throw 'a string' oder throw 42. Ein geworfener string hat keine message, keinen name und keinen stack, sodass Aufrufer, die ein Error-Objekt erwarten (wie es die meisten Codebases tun), sich falsch verhalten. Für domänenspezifische Fehler mit zusätzlichen Feldern definieren Sie Ihre eigene Klasse — siehe Benutzerdefinierte Fehler, Error erweitern.
Das Error-Objekt
Wenn Sie new Error(message) aufrufen, erhalten Sie ein Objekt mit drei häufig verwendeten Eigenschaften:
name— der Fehlertyp, z. B."Error","TypeError","SyntaxError".message— die lesbare Beschreibung, die Sie dem Konstruktor übergeben haben.stack— ein string mit dem Call-Stack zum Zeitpunkt der Fehlererstellung (nicht standardisiert, aber von jeder gängigen Engine unterstützt; gut zum Debuggen, nicht zur Ablaufsteuerung).
Eingebaute Fehlertypen
JavaScript liefert mehrere Error-Unterklassen, die die Engine automatisch wirft. Sie zu kennen hilft Ihnen, präzise catch-Logik zu schreiben:
| Typ | Wird geworfen, wenn |
|---|---|
SyntaxError | Code oder Daten fehlerhaft sind, z. B. JSON.parse() auf ungültigem JSON. |
TypeError | Ein Wert nicht den erwarteten Typ hat, z. B. eine Nicht-Funktion aufgerufen oder eine Eigenschaft von undefined gelesen wird. |
ReferenceError | Eine nicht existierende Variable referenziert wird. |
RangeError | Ein Wert außerhalb des erlaubten Bereichs liegt, z. B. eine ungültige array-Länge. |
URIError | decodeURIComponent() oder Ähnliches eine fehlerhafte URI erhält. |
EvalError | Historisch; wird von modernen Engines selten geworfen. |
Jeder dieser Typen hat name auf seinen Typnamen gesetzt, sodass Sie mit instanceof verzweigen können:
Bestimmte Fehler behandeln
Sie können auch bestimmte Fehlertypen behandeln, indem Sie das Fehlerobjekt untersuchen:
Dieses Beispiel behandelt speziell SyntaxError, der beim JSON-Parsing auftreten kann. Wenn der abgefangene Fehler eine Instanz von SyntaxError ist, wird er durch die Ausgabe einer spezifischen Meldung behandelt. Andernfalls wird der Fehler erneut geworfen, um möglicherweise von einem übergeordneten Fehlerhandler abgefangen oder um das Programm zu beenden, was auf ein unbehandeltes Fehlerszenario hinweist.
Fehler erneut werfen (Rethrowing)
Ein catch-Block fängt jeden Fehler in seinem try ab, einschließlich solcher, die man nicht behandeln kann. Das empfohlene Muster lautet: Den Fehler untersuchen, die verstandenen Fälle behandeln und alles andere erneut werfen, damit es sich zu einem äußeren Handler fortpflanzt. Unbekannte Fehler stillschweigend zu verschlucken verbirgt echte Bugs.
Optionales Catch-Binding
Wenn der Fehlerwert nicht benötigt wird, kann das Binding vollständig weggelassen werden (ES2019+). Dies ist nützlich, wenn nur die Tatsache, dass etwas fehlgeschlagen ist, relevant ist:
Finally verwenden
Die finally-Klausel wird nach den try- und catch-Blöcken ausgeführt, unabhängig davon, ob eine Exception geworfen oder abgefangen wurde. Sie ist nützlich zum Freigeben von Ressourcen oder für Aufräumarbeiten, unabhängig vom Ergebnis des try...catch:
Dadurch wird sichergestellt, dass die Meldung "Finally block executed" protokolliert wird, unabhängig davon, ob ein Fehler auftritt oder nicht — und demonstriert, wie finally für notwendige Aufräumaktionen verwendet werden kann.
Reale API-Anfrage-Beispiele
Die Verwendung der JSONPlaceholder API ist eine hervorragende Möglichkeit, den Umgang mit echten Daten in JavaScript zu üben, insbesondere beim Arbeiten mit asynchronen Anfragen und der Behandlung potenzieller Fehler, die dabei auftreten können. Hier sind einige praxisnahe Beispiele mit der JSONPlaceholder API, die gefälschte Online-REST-Daten bereitstellt, mit denen man für Tests und Prototypen experimentieren kann.
Beispiel 1: Posts abrufen und Fehler behandeln
In diesem Beispiel rufen wir Posts von der JSONPlaceholder API mit fetch ab und behandeln potenzielle Netzwerkfehler oder Probleme mit der API-Antwort:
Dieses Skript sendet eine HTTP-Anfrage, um ein einzelnes Todo-Element abzurufen. Es prüft, ob die Antwort erfolgreich ist (d. h. HTTP-Status 200-299). Falls nicht, wird ein Fehler mit dem Antwortstatus geworfen. Alle Fehler — sei es durch Netzwerkprobleme oder die throw-Anweisung — werden im catch-Block abgefangen und protokolliert. Der finally-Block wird unabhängig vom Ergebnis ausgeführt und stellt sicher, dass alle notwendigen Aufräum- oder abschließenden Operationen durchgeführt werden.
Beispiel 2: Daten senden und Exceptions behandeln
Hier zeigen wir, wie Daten mit der POST-Methode an den Server gesendet und Exceptions angemessen behandelt werden:
In diesem Skript senden wir einen neuen Post an den Server. Die fetch-Funktion wird mit der POST-Methode verwendet, einschließlich Header und einem JSON-serialisierten Body. Wenn die Serverantwort auf einen Fehler hinweist (nicht-2xx-HTTP-Status), wird ein Fehler geworfen, der im catch-Block abgefangen und behandelt wird. Unabhängig von Erfolg oder Misserfolg stellt der finally-Block sicher, dass die Operation als abgeschlossen markiert wird.
Beispiel 3: Einen Fehler absichtlich auslösen und behandeln
Dieses Beispiel fordert absichtlich eine Benutzer-ID an, die auf der JSONPlaceholder API nicht existiert, und löst damit einen 404-Not-Found-Fehler aus, den wir abfangen und behandeln.
Wie dieses Beispiel funktioniert
- Ungültiger API-Endpunkt: Die
fetch-Funktion wird mit einer URL aufgerufen, die eine ungültige Benutzer-ID (99999) enthält. Da JSONPlaceholder typischerweise keinen Benutzer mit diesem Index hat, gibt die API einen 404-Fehler zurück. - Gültigkeit der Antwort prüfen: Der Code prüft, ob der Antwortstatus nicht im erfolgreichen Bereich (200-299) liegt. Da die Benutzer-ID ungültig ist, wird die API-Antwort wahrscheinlich 404 sein, was unsere Fehlerbehandlung in der
if (!response.ok)-Prüfung auslöst. - Fehler werfen: Da die Antwort nicht OK ist, wird ein Fehler mit einer Meldung geworfen, die den HTTP-Status enthält — in diesem Fall ein 404-Not-Found-Fehler.
- Catch-Block: Der Catch-Block fängt den geworfenen Fehler ab und protokolliert eine spezifische Meldung mit
console.log. Dies liefert klares Feedback darüber, was schiefgelaufen ist. - Finally-Block: Dieser Block wird für Aufräumarbeiten oder abschließende Anweisungen verwendet und zeigt den Abschluss des Versuchs an, unabhängig vom Ergebnis.
Warum Try...Catch keine asynchronen Callback-Fehler abfangen kann
Dies ist die häufigste Fallgrube bei try...catch. Die Anweisung ist synchron: Sie fängt nur Fehler ab, die geworfen werden, während der try-Block gerade läuft. Wenn Sie einen Callback mit setTimeout, einem Event-Listener oder einem nicht-awaited Promise planen, läuft der Callback später — nachdem try...catch bereits beendet wurde und der Call-Stack leer ist. Zu diesem Zeitpunkt gibt es kein umschließendes try, das etwas abfangen könnte.
Um den Fehler zu behandeln, muss try...catch innerhalb des Callbacks platziert werden, wo der Fehler tatsächlich geworfen wird:
Dieselbe Regel erklärt, warum try...catch mit async/await funktioniert, aber nicht mit reinen Promises. await pausiert die Funktion und setzt sie im gleichen logischen Ablauf fort, sodass ein abgelehntes Promise als geworfener Fehler erscheint, den das try abfangen kann. Ein Promise, das nicht awaitet wird, wird unabhängig abgewickelt und umgeht das umschließende try vollständig — stattdessen muss .catch() verwendet werden.
Für eine tiefergehende Behandlung von asynchroner Fehlerbehandlung, siehe Fehlerbehandlung mit Promises und async/await.
Fazit
Effektive Fehlerbehandlung in JavaScript ist der Schlüssel zur Entwicklung hochwertiger, robuster Anwendungen. Mit try...catch können Sie synchrone Fehler und awaitete Ablehnungen kontrolliert behandeln und dabei die Kontrolle über den Anwendungsablauf behalten. Werfen Sie Error-Objekte (niemals bloße strings), verzweigen Sie auf eingebaute Typen wie TypeError und SyntaxError, werfen Sie alles erneut, was Sie nicht behandeln können, und denken Sie an die asynchrone Einschränkung: Fehler in Callbacks und nicht-awaited Promises benötigen ihre eigene Behandlung.
Verwandte Themen
- Benutzerdefinierte Fehler, Error erweitern — eigene Fehlerklassen definieren.
- Fehlerbehandlung mit Promises —
.catch()und Ablehnungsablauf. - Async/await —
try...catchmit asynchronem Code. - Mit JSON arbeiten —
JSON.parseund derSyntaxError, den es werfen kann.