Finde den Fehler

Error Handling in JavaScript
Kommentare

Webapplikationen leben von der Interaktion mit dem Benutzer. Und vor allem in dieser Umgebung kommt es immer wieder zu Ausnahmesituationen. Sei es, dass der Benutzer die Software anders verwendet, als der Entwickler es vorgesehen hat, oder ein Server nicht oder mit falschen Daten antwortet. An sämtliche dieser Situationen müssen Sie bei der Entwicklung Ihrer Applikation denken und Routinen vorsehen, die in der Lage sind, mit solchen Ausnahmen umzugehen.

Gerade der Umgang mit Fehlern und Ausnahmen wird bei der Entwicklung von Webapplikationen häufig vernachlässigt. Doch wer es versäumt, bereits in der Entwicklung entsprechendes Error Handling zu berücksichtigen, läuft Gefahr, dass die Applikation unerwartet beendet wird, was meistens in einer Beeinträchtigung der Benutzung mündet. Aus diesem Grund erfahren Sie in diesem Artikel, welche Arten von Fehlern in einer JavaScript-Applikation auftreten können und wie Sie mit diesen Fehlern umgehen können. Außerdem möchte ich Ihnen einige Best Practices mit auf den Weg geben.

Fehlertypen in JavaScript

In JavaScript werden Sie mit verschiedenen Typen von Fehlern konfrontiert. Auf einige davon können Sie reagieren, auf andere nicht. JavaScript selbst verwendet sechs Basistypen von Fehlern. Diese leiten sich alle von einem allgemeinen Fehler, dem Error-Typ, ab. Diese sechs Fehlertypen lauten:

  • SyntaxError
  • EvalError
  • RangeError
  • ReferenceError
  • TypeError
  • URIError

Abbildung 1 zeigt Fehlermeldungen, die in der Konsole abgefangen werden.

Abb. 1: Konsole Fehlermeldung

Abb. 1: Konsole Fehlermeldung

SyntaxError

Der erste Fehlertyp in JavaScript, den ich Ihnen hier vorstellen möchte, ist der SyntaxError. SyntaxErrors treten auf, wenn Sie, wie der Name vermuten lässt, gegen die Sprachsyntax von JavaScript verstoßen. Vergessen Sie beispielsweise nach einer öffnenden geschweiften Klammer diese im Verlauf Ihres Skripts wieder zu schließen, führt dies zu einem SyntaxError. Ein SyntaxError kann nicht ohne Weiteres gefangen werden und führt aus diesem Grund zum Abbruch Ihrer Applikation.

EvalError

Ein EvalError wird verursacht, wenn die eval-Funktion von JavaScript nicht korrekt verwendet wird. Der ECMAScript-3-Standard sieht diesen Fehler vor, wenn eval indirekt aufgerufen wird – also wenn die Funktion eval einer anderen Variablen zugewiesen und dann aufgerufen wird. Da Sie die eval-Funktion nur mit Bedacht einsetzen sollten, sollten Sie auch mit EvalErrors nur sehr selten in Berührung kommen.

RangeError

RangeErrors entstehen, wenn Sie bei der Verwendung einer Funktion auf unerlaubte Zahlenbereiche zugreifen. Erstellen Sie beispielsweise ein Array mit einer ungültigen Anzahl von Elementen, wie -1, wird ein RangeError geworfen. Aber auch bei anderen Funktionen, die mit Zahlen zu tun haben, wie der toFixed-Methode, können Sie bei falscher Verwendung mit RangeErrors in Kontakt kommen. Diese Art von Fehlern können Sie allerdings fangen und entsprechend behandeln.

ReferenceError

Mit dem ReferenceError werden Sie wohl am häufigsten in Kontakt kommen. Dieser Fehler tritt auf, wenn Sie versuchen, auf eine nicht deklarierte Variable zuzugreifen. Schreiben Sie also beispielsweise bei der Erzeugung eines neuen Arrays nicht new Array, sondern new Arry, wird dies mit einem ReferenceError quittiert. Mithilfe der Fehlerbehandlungsroutinen, die Ihnen JavaScript zur Verfügung stellt, können Sie auch mit dieser Art von Fehlern umgehen.

TypeError

Fehler der Kategorie TypeError treten auf, wenn Sie die falschen Datentypen verwenden. Obwohl JavaScript zu den nicht typsicheren Sprachen zählt, gibt es trotzdem verschiedene Stellen, an denen Sie auf den korrekten Typ achten müssen. So können Sie zum Beispiel verschiedene String-Methoden nicht auf ein Zahlenobjekt anwenden. Diese Art von Fehler können Sie innerhalb Ihrer JavaScript-Applikation abfangen und damit umgehen.

URIError

Der letzte Typ von Fehlern, mit dem Sie bei der Arbeit mit JavaScript konfrontiert werden, ist der URIError. Diese Art von Fehler wird geworfen, wenn Sie versuchen, einer der URI-Funktionen wie beispielsweise decodeURI einen ungültigen Wert zu übergeben. Wie bei den meisten anderen Fehlertypen von JavaScript können Sie auch Fehler vom Typ URIError abfangen und mit dem Fehler umgehen. Neben den Fehlertypen, die Ihnen JavaScript zur Verfügung stellt, können Sie auch eigene Fehler definieren. Was das für Ihre Applikation bedeutet, erfahren Sie im Folgenden.

Eigene Fehler

Wie in vielen anderen Programmiersprachen können Sie auch in JavaScript Exceptions werfen. Das sind Fehlermeldungen, die dafür sorgen, dass Ihre Applikation abgebrochen wird, wenn Sie nicht korrekt gefangen werden. Exceptions werden generell mit dem throw-Statement geworfen. Sie sollten sie immer dann verwenden, wenn ein unerwarteter Fehler oder eine andere Ausnahmesituation innerhalb Ihrer Applikation auftritt, die speziell behandelt werden muss. Im einfachsten Fall geben Sie nach dem throw lediglich eine Zeichenkette an. Dann ist die Aussagekraft der Fehlermeldung allerdings nur begrenzt. Viel besser können Sie den Exception-Mechanismus von JavaScript mit Fehlerobjekten ausnutzen.

In JavaScript steht Ihnen, um aussagekräftigere Exceptions zu werfen, eine Konstruktor-Funktion Error zur Verfügung. Fehler vom Typ Error stellen die allgemeinsten Fehler dar. Von diesem Typ leiten auch die übrigen Fehlertypen wie beispielsweise der ReferenceError oder der URIError ab. Dieser allgemeine Fehlertyp enthält die Eigenschaften name und message, wobei die Eigenschaft name den Typ des Fehlers bezeichnet und im Falle eines allgemeinen Fehlers den Wert Error enthält. Die Eigenschaft message enthält die Beschreibung des Fehlers. Diese Beschreibung übergeben Sie der Konstruktor-Funktion bei der Erzeugung als Argument. Als Methode stellt Ihnen das Fehlerobjekt lediglich die toString-Methode zur Verfügung, mit deren Hilfe Sie eine String-Repräsentation des Fehlers erhalten. Damit Sie nun eine Exception vom Typ Error werfen können, verbinden Sie das throw-Statement mit einer konkreten Instanz des Fehlers, den Sie mit dem new Operator und dem Error-Konstruktor erhalten. Beim Werfen von Exceptions sind Sie allerdings nicht auf Fehler vom Typ Error beschränkt, sondern können auch Instanzen der übrigen sechs Standardfehler verwenden. So können Sie beispielsweise auch einen SyntaxError werfen.

Reichen Ihnen diese Fehlertypen nicht aus, können Sie auch eine eigene Konstruktor-Funktion erstellen und diese von Error ableiten. Eine noch einfachere Variante besteht darin, dass Sie ein Objektliteral erzeugen, das sowohl die Eigenschaften name als auch message enthält. Dieses Objekt können Sie ebenfalls mit dem throw-Statement werfen. In Listing 1 sehen Sie, wie das konkret im Quellcode aussehen kann.

try {
  throw {
    name: 'Application Error',
    message: 'The data you provided is insufficient'
  }
} catch (e) {
  console.log(e);
}

Nachdem Sie nun wissen, wie Sie Fehler erzeugen, erfahren Sie als Nächstes, wie Sie mit Fehlern innerhalb Ihrer Applikation umgehen können.

Umgang mit Fehlern

Nicholas C. Zakas, Frontend Engineer, Autor und Speaker, hielt einen Vortrag mit dem Titel „Enterprise JavaScript Error Handling“, in dem er sich dem Thema der Fehlerbehandlung in JavaScript widmete. In diesem Vortrag stellt Zakas einige sehr wertvolle Best Practices vor. Diese lernen Sie nun näher kennen:

1. Gehen Sie davon aus, dass Ihr Code fehlschlägt. 2. Halten Sie die Fehler auf dem Server fest. 3. Finden Sie heraus, wo Fehler auftreten können. 4. Werfen Sie Ihre eigenen Fehler. 5. Unterscheiden Sie zwischen schwerwiegenden und nicht schwerwiegenden Fehlern. 6. Stellen Sie einen Debug-Modus zur Verfügung. 7. Sie, und nicht der Browser, behandeln die Fehler.

Der erste Punkt ist der wichtigste im Umgang mit Fehlern in JavaScript. Sie sollten stets davon ausgehen, dass Teile Ihrer Applikation fehlschlagen. Vor allem im Bereich der Benutzerinteraktion treten häufig Situationen auf, in denen sich der Benutzer nicht verhält, wie Sie es von ihm erwarten. In diesen Fällen sollten Sie auf Exceptions zurückgreifen. Erwarten Sie beispielsweise, dass eine Funktion eine Zahl als Argument erhält, und ein Benutzer stattdessen eine Zeichenkette zur Verfügung stellt, können Sie die Eingabe validieren und bei einer falschen Eingabe eine Exception mit einer entsprechenden Fehlermeldung werfen.

Während der Entwicklung Ihrer Applikation testen Sie die implementierte Logik immer wieder. Dennoch kann es vorkommen, dass Sie nicht sämtliche Möglichkeiten vorgesehen und geprüft haben. Ist Ihre Applikation erst einmal live und wird von Benutzern verwendet, kommt es immer wieder vor, dass Benutzer Fehler in Ihrer Applikation finden. Damit Sie von diesen Fehlern erfahren, sollten Sie dafür sorgen, dass die Fehler zum Server gesendet werden.

Für die Implementierung einer korrekten Fehlerbehandlungsroutine müssen Sie wissen, an welchen Stellen Fehler auftreten können. Diese Stellen finden Sie vor allem an Schnittstellen zu anderen Systemen. Hier haben Sie keine Kontrolle, wie Ihre Funktionen verwendet werden und müssen aus diesem Grund Fehlerfälle absichern. Tritt ein solcher Fehlerfall auf, müssen Sie den Benutzer darauf aufmerksam machen. Im Normalfall prüfen Sie eine Eingabe, das Ergebnis einer Berechnung oder sonstige Schlüsselstellen Ihrer Applikation und werfen, falls nötig, eine Exception. Wie Sie bereits gesehen haben, stehen Ihnen verschiedene Arten von Exceptions zur Verfügung. Je detaillierter Sie den Fehler melden, desto hilfreicher ist die Meldung für denjenigen, der mit der Fehlermeldung umgeht. Das bedeutet wiederum, dass Sie nicht auf Exceptions vom Typ Error zurückgreifen, sondern stattdessen für verschiedene Situationen spezialisierte Fehlertypen verwenden sollten.

In Ihrer Applikation können verschiedene Arten von Fehlern auftreten. Diese Fehler lassen sich grob in drei Kategorien unterteilen. Die erste und schwerwiegendste Kategorie besteht aus Fehlern, die eine Benutzung der gesamten Applikation unmöglich machen. In der zweiten Kategorie finden sich Fehler, die die Verwendung von Teilen der Applikation verhindern. Die dritte Kategorie enthält schließlich Fehler, die zwar negative Auswirkungen auf die Applikation haben, aber eine Benutzung der Kernkomponenten nicht verhindern. Die Fehler, die potenziell in Ihrer Applikation auftreten können, sollten Sie in diese Kategorien einordnen. Dadurch wissen Sie, wie viel Zeit Sie in die jeweiligen Stellen investieren sollten. Die Behandlung von Fehlern der ersten Kategorie sollte auf jeden Fall Priorität haben.

Gerade während der Entwicklung einer Applikation sollten Sie einen Debug-Modus vorsehen. Dieser ermöglicht Ihnen einen Blick hinter die Kulissen, indem an verschiedenen Punkten in Ihrer Applikation Statusinformationen ausgegeben werden. Für die Ausgabe dieser Debug-Informationen gibt es mehrere Möglichkeiten. Die einfachste besteht darin, dass Sie die Daten auf die JavaScript-Konsole schreiben. Eine weitere Variante ist, dass Sie ein HTML-Element für den Debug-Modus in Ihre Seite einbauen und hier die Informationen ausgeben. Bei der Umsetzung des Debug-Modus sollten Sie vorsehen, dass Sie ihn auf einfache Weise ein- und wieder ausschalten können. Dies können Sie beispielsweise über eine Konfigurationsvariable realisieren. Für den Produktivbetrieb ist es des Weiteren möglich, die Statements des Debug-Modus automatisiert vor einem Skript entfernen zu lassen.

Der letzte Punkt besagt, dass nicht der Browser, sondern Sie selbst für die Behandlung der Fehler verantwortlich sind. Der folgende Abschnitt stellt Ihnen den Standardmechanismus vor, auf den Sie in JavaScript zurückgreifen können.

Workflow der Fehlerbehandlung

Der einfachste Weg mit Fehlern umzugehen, besteht aus der Verwendung des try-catch-Statements. Falls Sie bereits mit anderen Programmiersprachen gearbeitet haben, kommt Ihnen dieses Statement wahrscheinlich bekannt vor – Programmiersprachen wie C, Java und PHP bieten ebenfalls try-catch-Statements an. Das Ziel dieses Statements ist in allen Sprachen das gleiche: Der Codeblock, der auf das try-Statement folgt, wird ausgeführt. Tritt in diesem Quellcode ein Fehler auf, der dazu führt, dass eine Exception geworfen wird, wird der Quellcode im catch-Block ausgeführt. In typsicheren Sprachen haben Sie den Vorteil, dass Sie mehrere catch-Blöcke hintereinander schalten und darin jeweils unterschiedliche Typen von Exceptions fangen können. Diese Möglichkeit bietet JavaScript nicht. Das bedeutet konkret, dass Sie einen try-Block und einen zugehörigen catch-Block angeben. JavaScript verfügt zusätzlich zu den beiden Statements try und catch über das finally-Statement. Der Block, der auf dieses Statement folgt, wird immer ausgeführt – egal, ob im try-Block ein Fehler aufgetreten ist oder nicht. Diesen Block sollten Sie dazu verwenden, um verschiedene Aufräumarbeiten zu erledigen. Listing 2 zeigt Ihnen die Verwendung von try, catch und finally.

try {
  // ReferenceError
  console.log(myUndefinedProperty);
} catch (e) {
  // Ausgabe des Fehlers
  console.log(e);
} finally {
  // dieser Block wird immer ausgeführt
  console.log('cleanup');
}

Ein Anti-Pattern im Umgang mit Exception ist das so genannte catch-all. In diesem Fall kapseln Sie Ihre gesamte Applikationslogik oder zumindest einen großen Teil dieser in einem try-Block. Tritt irgendwo in Ihrer Applikation ein Fehler auf, wird er spätestens durch den zugehörigen globalen catch-Block gefangen und behandelt. Der entscheidende Nachteil dieser Vorgehensweise ist, dass die Fehler nicht dort behandelt werden, wo sie auftreten und wo Sie direkt reagieren können, sondern an einer zentralen Stelle. Hier laufen die Fehler von so vielen verschiedenen Stellen zusammen, dass es nahezu unmöglich ist, auf jeden Fehler korrekt zu reagieren. Hier können Sie lediglich eine allgemeine Fehlermeldung ausgeben.

Zwischen dem Abfangen von Fehlern mit try-catch und der Fehlerbehandlung durch den Browser selbst existiert noch ein Zwischenschritt. Mit dem onerror-Handler können Sie auf Fehler in Ihrer Applikation reagieren. Auch diese Variante greift auf globaler Ebene und ist generell nicht für die Fehlerbehandlung in einer Applikation zu empfehlen. Um den onerror-Handler zu nutzen, weisen Sie der Eigenschaft window.onerror eine Funktion zu. Diese Funktion wird dann beispielsweise aufgerufen, falls in Ihrer Applikation ein Fehler geworfen und dieser nicht durch ein try-catch gefangen wird. Der onerror-Handler soll Ihnen lediglich zur Protokollierung von Fehlern dienen. Diese Stelle eignet sich also sehr gut, um eine Routine zu erstellen, die die aufgetretenen Fehler per AJAX zum Server schickt, damit dieser das Problem zur späteren Analyse festhält. Die Fehler, die den Aufruf der Callback-Funktion verursachen, werden trotzdem an den Browser weitergegeben, was in den meisten Fällen zu einem Abbruch Ihrer Applikation führt. Als Argumente erhalten Sie in der Callback-Funktion des onerror-Handlers die Zeichenkette, die den Fehler repräsentiert, die Datei, in der der Fehler aufgetreten ist, und die Nummer der Zeile, die den Fehler enthält. Das bedeutet, dass Sie mit diesem Mittel auftretende Fehler gut lokalisieren können.

Umgang mit Exceptions

Einen Punkt, den Sie im Zusammenhang mit Exceptions beachten sollten, ist, dass Exceptions zur Ausnahmebehandlung dienen. Das bedeutet aber auch, dass Sie diesen Mechanismus nicht zur Steuerung des normalen Programmablaufs verwenden sollten. Eine Exception in Verbindung mit einem try-catch-Statement ist also kein Ersatz für ein if-Statement. Neben der Zweckentfremdung von Exception hat dies auch einen einfachen performancerelevanten Hintergrund. Der Umgang mit Exceptions ist um ein Vielfaches langsamer als ein entsprechendes if-Statement. Für die Entwicklung bedeutet das konkret, dass Sie in Ihrer Logik die Standardfälle mit if-Abfragen abdecken sollten. Bei Eingaben oder Fällen, die Ausnahmen darstellen, mit denen Sie nicht umgehen können, beziehungsweise nicht umgehen möchten, setzen Sie Exceptions ein.

Greifen Sie in Ihrer Applikation beispielsweise auf eine Eigenschaft eines Objekts zu, sollten Sie vor diesem Zugriff sicherstellen, dass die Eigenschaft auch existiert. Beim Zugriff auf primitive Datentypen wie Zahlen oder Zeichenketten ist es auch kein Problem, wenn Sie zuvor nicht abfragen, ob die Eigenschaft existiert. In diesem Fall erhalten Sie lediglich den Wert undefined zurück. Problematischer wird die Situation, wenn Sie versuchen, auf eine Eigenschaft eines Objekts zuzugreifen, die wiederum in einer Eigenschaft eines Objekts liegt. Gehen Sie davon aus, Sie haben ein Objekt rectangle, also ein Rechteck. Dieses weist neben den Eigenschaften height und width, die einfache Zahlenwerte enthalten, noch die Eigenschaft position auf. position ist wiederum ein Objekt mit den Eigenschaften x und y. Besitzt Ihr rectangle nun aber diese Eigenschaft position nicht und Sie greifen trotzdem über rectangle.position.x auf die X-Koordinate der Position zu, wird dies von Ihrem Browser mit einer Exception vom Typ TypeError quittiert. Dieses Problem können Sie umgehen, indem Sie vor dem Zugriff abfragen, ob rectangle über eine position-Eigenschaft verfügt. Ist dies nicht der Fall, können Sie die Position des Objekts bestimmen und die Eigenschaft mit einem Standardwert vorbelegen. Neben diesem Ansatz existieren für JavaScript jedoch noch zahlreiche weitere Möglichkeiten, wie Sie mit Fehlern in Ihrer Applikation umgehen können.

Fehlerobjekte in Callbacks

Eine Variante der Fehlerbehandlung, die aus der asynchronen Programmierung stammt, ist die Verwendung von Fehlerobjekten in Callback-Funktionen. Im Kern besteht diese Methode daraus, dass eine Callback-Funktion, die aufgrund einer asynchronen Operation aufgerufen wird, als Argument ein Fehlerobjekt erhält. Innerhalb der Callback-Funktion liegt es dann an Ihnen als Entwickler, mit dem Fehler entsprechend umzugehen. Diese Vorgehensweise hat sich vor allem in der serverseitigen JavaScript-Plattform Node.js als De-facto-Standard durchgesetzt. Hierbei ist das erste Argument einer Callback-Funktion in der Regel das Fehlerobjekt. Alle weiteren Daten, die zur weiteren Verarbeitung der Ergebnisse der asynchronen Operation notwendig sind, werden als weitere Argumente an die Callback-Funktion übergeben. Doch was geschieht, wenn innerhalb der Operation kein Fehler auftritt, was eigentlich die Regel sein sollte? In diesem Fall weist das Fehlerobjekt den Wert null auf, sodass Sie mit einer einfachen if-Abfrage prüfen können, ob ein Fehler aufgetreten ist. Im Idealfall sollten die hier verwendeten Objekte vom allgemeinen Fehlertyp ableiten und zumindest die Eigenschaften name und message aufweisen. Durch diese einheitliche Struktur erreichen Sie eine Entkopplung und damit eine gute Wartbarkeit und Erweiterbarkeit Ihrer Applikation. Diese Art der Fehlerbehandlung kommt also komplett ohne try-catch-Statements aus. In Listing 3 sehen Sie, wie diese Art der Fehlerbehandlung im Dateisystemmodul von Node.js zum Einsatz kommt.

fs.readFile('/tmp/input.txt', function (err, data) {
  if (err) {
    console.log('An error occurred' + err);
  };
  console.log(data);
});

Eine weitere Variante der Fehlerbehandlung ergibt sich aus einer eventgetriebenen Architektur, wie Sie von JavaScript sehr gut unterstützt wird.

Error Events

JavaScript erlaubt Ihnen durch verschiedene Sprachkonstrukte, wie beispielsweise anonyme Funktionen, sehr einfach eine eventbasierte Architektur umzusetzen. Im Normalfall existieren hier eine oder mehrere Quellen für Ereignisse, an die verschiedene Callback-Funktionen gebunden werden können. In jQuery binden Sie mithilfe der on-Methode eine Callback-Funktion an eine solche Eventquelle. Intern lässt sich eine derartige Struktur als Stack umsetzen, auf den durch die on-Methode die Callback-Funktionen gelegt werden. In bestimmten Situationen können Sie dann ein Event auslösen. In diesem Fall müssen Sie dafür sorgen, dass alle Callback-Funktionen, die auf dieses Event gebunden sind, ausgeführt werden. Eine konkrete Implementierung könnte beispielsweise darin bestehen, dass Sie über den zuvor erwähnten Stack von Callback-Funktionen iterieren und die Callback-Funktionen nacheinander aufrufen. jQuery bietet Ihnen zum Auslösen eines Events die trigger-Methode. Das erste Argument gibt den Typ des Events an, im zweiten Argument können Sie weitere Informationen an die Callback-Funktionen übergeben.

Soweit hat dieses Konstrukt noch nichts mit der Fehlerbehandlung in Ihrer Applikation zu tun. Es ist allerdings möglich, dass Sie innerhalb Ihres Codes Events vom Typ error auslösen und Callbacks daran binden. Wie Sie Ihre Events benennen und in welchen Situationen Sie diese auslösen, liegt in Ihrer Verantwortung. Im Falle des error-Events können Sie Ihre Implementierung des EventEmitters, also der Quelle von Events, dahingehend erweitern, dass eine Exception geworfen wird, wenn keine Callback-Funktion zur Behandlung eines error-Events existiert, wenn ein solches ausgelöst wird. Damit erzwingen Sie, dass mit error-Events umgegangen wird, da ansonsten Ihre Applikation mit einem Fehler abgebrochen wird.

Fehlerbehandlung bei Promises

Eine Methode der Fehlerbehandlung, die bei der asynchronen Programmierung eingesetzt wird, sind Promises. Eine Promise stellt dabei den Rückgabewert einer asynchronen Operation dar. Dieser Wert existiert zum Zeitpunkt des Aufrufs der asynchronen Operation noch nicht. Jede Logik, die auf diesem Rückgabewert aufbaut, kann erst ausgeführt werden, wenn das Ergebnis der Operation vorliegt. Zu diesem Zeitpunkt wird die Promise dann aufgelöst oder abgewiesen. Die Auflösung bedeutet, dass die Operation erfolgreich war. Eine Abweisung stellt einen Fehler dar. Je nachdem, welcher Fall eintritt, werden unterschiedliche Callback-Funktionen ausgeführt. Seit der Version 1.5 von jQuery ist das Konzept der Promises beispielsweise fest in jQuery verankert und kommt unter anderem bei jQuery.ajax zum Einsatz.

In jQuery wird ein Objekt vom Typ Deferred erstellt. Dieses Objekt stellt den Rückgabewert der Operation dar. Der Rückgabewert von jQuery.ajax stellt beispielsweise ein solches Deferred-Objekt dar. Für den Fall, dass diese Operation erfolgreich ist, binden Sie mit der done-Methode eine Callback-Funktion an die Promise. Im Fehlerfall wird die Callback-Funktion ausgeführt, die Sie mit einem Aufruf der fail-Methode an die Promise binden. Ähnlich zum finally im try-catch-Statement existiert die always-Methode, die in jedem Fall ausgeführt wird, unabhängig davon, ob die Promise aufgelöst oder abgewiesen wird. Sie können diese Methoden auch mehrmals aufrufen und damit mehrere Callback-Funktionen des gleichen Typs an eine Promise binden. Ist die Operation, die an die Promise geknüpft ist, erfolgreich, lösen Sie die Promise mit einem Aufruf der resolve-Methode auf. Rufen Sie die reject-Methode der Promise auf, gilt die Operation als fehlgeschlagen und die Promise wird abgewiesen. Listing 4 zeigt Ihnen, wie Sie beispielsweise in jQuery Promises verwenden können.

$.ajax({
  url: 'http://localhost:8080/user/4'
}).done(function (data) {
  // success callback
}).fail(function () {
  // error callback
});

Die hier beschriebenen Methoden stellen lediglich einen kleinen Teil der Möglichkeiten dar, die Ihnen durch die Promises in Form des Deferred-Objekts zur Verfügung stehen. Abschließend lernen Sie nun noch ein Konzept zur Fehlerbehandlung für Node.js kennen.

Node.js Domain

Node.js bietet Ihnen zum Umgang mit Fehlern neben den bisher genannten Varianten zusätzlich noch das Domain-Modul, mit dem Sie mit einer Domain einen Bereich definieren können, für den Sie Fehler, ähnlich zu window.onerror, fangen können. Im Gegensatz zu dieser Variante sorgt die Fehlerbehandlungsroutine der Domain dafür, dass Ihre Applikation nicht beendet wird, sondern der Fehler korrekt behandelt wird, ähnlich dem catch-Block im try-catch-Statement.

Die Domain generieren Sie mit der Domain.create-Methode. Das dadurch entstandene Objekt stellt Ihnen die run-Methode zur Verfügung. Diese erhält eine Funktion als Argument, die den Applikationscode beinhaltet, der innerhalb der Domain ausgeführt werden soll. Alternativ dazu können Sie einzelne Funktionen mit der bind-Methode des Domain-Objekts an die Domain binden. Wird innerhalb des an die Domain gebundenen Codes ein error-Event ausgelöst oder eine Exception geworfen, wird die von Ihnen angegebene Fehlerbehandlungsroutine ausgeführt. Diese Routine arbeitet nach einem eventbasierten Ansatz. Sie erstellen also eine Callback-Funktion und binden Sie mithilfe der on-Methode der Domain an das error-Event der Domain.

Das Domain-Modul ist vor allem zur Fehlerbehandlung im Child-Process-Kontext geeignet. Sie können innerhalb der Fehlerbehandlungsroutine dafür sorgen, dass der Kind-Prozess korrekt heruntergefahren wird und dem Eltern-Prozess signalisieren, dass eine bestimmte Ausnahmesituation aufgetreten ist. Der Eltern-Prozess kann nun wiederum auf diese Situation reagieren und gegebenenfalls einen neuen Kind-Prozess erzeugen.

Zusammenfassung

Die Möglichkeiten, die Ihnen bei der Fehlerbehandlung in JavaScript zur Verfügung stehen, sind vielfältig. Es liegt an Ihnen, die korrekte Methode für Ihren jeweiligen Einsatzzweck zu wählen. Die Wahl der korrekten Methode hängt unter anderem von Ihrer Umgebung ab. Setzen Sie beispielsweise viele asynchrone Operationen ein, können Sie Fehlerobjekte als Argumente Ihrer Callback-Funktionen verwenden oder auf das Konzept der Promises zurückgreifen. Möchten Sie Ihre Fehler lediglich protokollieren, können Sie eine Callback-Funktion für window.error definieren.

Je nachdem welche Variante der Fehlerbehandlung Sie verwenden, können Sie entweder auf Browsermittel zurückgreifen oder müssen das entsprechende Verhalten selbst implementieren. Da es sich in den meisten Fällen jedoch um Standards handelt, existieren hier zahlreiche Bibliotheken, die Ihnen einigen Implementierungsaufwand abnehmen. Allgemein sollten Sie beachten, dass Sie Exceptions nicht zur Steuerung des Programmflusses verwenden sollten, sondern, wie der Name andeutet, als ein Mittel zur Behandlung von Ausnahmesituationen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -