Welcome to Our Website

Benutzerdefinierte Fehler, Erweiterung Error

Wenn wir etwas entwickeln, benötigen wir oft unsere eigenen Fehlerklassen, um bestimmte Dinge widerzuspiegeln, die in unseren Aufgaben schief gehen können. Für Fehler in Netzwerkoperationen benötigen wir möglicherweise HttpError, für Datenbankoperationen DbError, für Suchoperationen NotFoundError und so weiter.

Unsere Fehler sollten grundlegende Fehlereigenschaften wie message, name und vorzugsweise stackunterstützen. Sie können aber auch andere eigene Eigenschaften haben, z., HttpError Objekte können einestatusCode Eigenschaft mit einem Wert wie404 oder403 oder500.

JavaScript erlaubt die Verwendung von throw mit jedem Argument, sodass unsere benutzerdefinierten Fehlerklassen technisch nicht von Errorerben müssen. Wenn wir jedoch erben, kann obj instanceof Error verwendet werden, um Fehlerobjekte zu identifizieren. Es ist also besser, davon zu erben.

Wenn die Anwendung wächst, bilden unsere eigenen Fehler natürlich eine Hierarchie., Zum Beispiel kann HttpTimeoutError von HttpError usw. erben.

Erweiterungsfehler

Betrachten wir als Beispiel eine Funktion readUser(json), die JSON mit Benutzerdaten lesen sollte.

Hier ist ein Beispiel, wie eine gültige json aussehen kann:

let json = `{ "name": "John", "age": 30 }`;

Intern verwenden wir JSON.parse. Wenn es eine fehlerhafte json empfängt, wird SyntaxError., Aber selbst wenn json syntaktisch korrekt ist, bedeutet das nicht, dass es ein gültiger Benutzer ist, oder? Es können die erforderlichen Daten fehlen. Zum Beispiel kann es nicht name und age Eigenschaften, die für unsere Benutzer wesentlich sind.

Unsere Funktion readUser(json) liest nicht nur JSON, sondern überprüft („validiert“) die Daten. Wenn keine erforderlichen Felder vorhanden sind oder das Format falsch ist, ist dies ein Fehler. Und das ist kein SyntaxError, weil die Daten syntaktisch korrekt sind, sondern eine andere Art von Fehler., Wir nennen es ValidationError und erstellen eine Klasse dafür. Ein solcher Fehler sollte auch die Informationen über das beleidigende Feld enthalten.

UnsereValidationError Klasse sollte von der integriertenError Klasse erben.

Diese Klasse ist eingebaut, aber hier ist ihr ungefährer Code, damit wir verstehen können, was wir erweitern:

Jetzt erben wir ValidationError davon und versuchen es in Aktion:

Bitte beachten Sie: In der Zeile (1) rufen wir den übergeordneten Konstruktor auf., JavaScript erfordert, dass wir super im untergeordneten Konstruktor aufrufen, also ist das obligatorisch. Der übergeordnete Konstruktor setzt die Eigenschaft message.

Der übergeordnete Konstruktor setzt auch die Eigenschaft name auf "Error", also setzen wir sie in der Zeile (2) auf den richtigen Wert zurück.,

Versuchen wir es in readUser(json):

Der try..catch Block im obigen Code behandelt sowohl unsere ValidationError als auch die integrierte SyntaxError von JSON.parse.

Bitte schauen Sie sich an, wie wir instanceof verwenden, um in der Zeile (*)nach dem spezifischen Fehlertyp zu suchen.,

Wir könnten uns auch err.name so ansehen:

// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...

DieinstanceofVersion ist viel besser, weil wir in ZukunftValidationError, machen Sie Untertypen davon, wiePropertyRequiredError. Und instanceof check funktioniert weiterhin für neue Erbendeklassen. Das ist also zukunftssicher.

Es ist auch wichtig, dass, wenn catch auf einen unbekannten Fehler trifft, dieser in der Zeile (**)., Dercatch Block weiß nur, wie man mit Validierungs-und Syntaxfehlern umgeht, andere Arten (aufgrund eines Tippfehlers im Code oder anderer unbekannter) sollten durchfallen.

Weitere Vererbung

DieValidationError Klasse ist sehr generisch. Viele Dinge können schief gehen. Die Eigenschaft fehlt möglicherweise oder hat ein falsches Format (z. B. einen Zeichenfolgenwert für age). Machen wir eine konkretere Klasse PropertyRequiredError, genau für abwesende Eigenschaften. Es wird zusätzliche Informationen über die Eigenschaft tragen, die fehlt.,

Die neue Klasse PropertyRequiredError ist einfach zu bedienen: Wir müssen nur den Eigenschaftsnamen übergeben: new PropertyRequiredError(property). Die vom Menschen lesbare message wird vom Konstruktor generiert.

Bitte beachten Sie, dass this.name in PropertyRequiredError der Konstruktor erneut manuell zugewiesen wird. Das kann etwas mühsam werden – this.name = <class name> in jeder benutzerdefinierten Fehlerklasse zuzuweisen. Wir können es vermeiden, indem wir unsere eigene „basic error“ – Klasse erstellen, die this.name = this.constructor.namezuweist. Und erben Sie dann alle unsere benutzerdefinierten Fehler davon.,

nennen wir es MyError.

Hier ist der Code mit MyError und anderen benutzerdefinierten Fehlerklassen, vereinfacht:

Jetzt sind benutzerdefinierte Fehler viel kürzer, insbesondere ValidationError, da wir die "this.name = ..." – Zeile im Konstruktor entfernt haben.

Wrapping exceptions

Der Zweck der Funktion readUser im obigen Code ist“zum Lesen der Benutzerdaten“. Es können verschiedene Arten von Fehlern im Prozess auftreten., Im Moment haben wir SyntaxError und ValidationError, aber in Zukunft readUser Funktion kann wachsen und wahrscheinlich andere Arten von Fehlern erzeugen.

Der Code, der readUser aufruft, sollte diese Fehler behandeln. Im Moment werden mehrere ifs im catch – Block verwendet, die die Klasse überprüfen und bekannte Fehler behandeln und die unbekannten überdenken.

Das Schema ist wie folgt:

Im obigen Code können wir zwei Arten von Fehlern sehen, aber es kann mehr geben.,

Wenn diereadUser – Funktion mehrere Arten von Fehlern generiert, sollten wir uns fragen: Möchten wir wirklich jedes Mal einzeln nach allen Fehlertypen suchen?

Oft lautet die Antwort „Nein“: Wir möchten“eine Ebene darüber“ sein. Wir wollen nur wissen, ob es einen „Datenlesefehler“ gab – warum genau es passiert ist, ist oft irrelevant (die Fehlermeldung beschreibt es). Oder, noch besser, wir möchten einen Weg haben, um die Fehlerdetails zu erhalten, aber nur, wenn wir müssen.

Die Technik, die wir hier beschreiben, heißt „wrapping exceptions“.,

  1. Wir erstellen eine neue Klasse , um einen generischen Fehler beim Lesen von Daten darzustellen.
  2. Die Funktion readUser fängt darin auftretende Datenlesefehler ab, z. B. ValidationError und SyntaxError, und generiert stattdessen eine .
  3. Das – Objekt behält den Verweis auf den ursprünglichen Fehler in seinercause – Eigenschaft bei.,

Dann muss der Code, der readUser aufruft, nur nach , nicht für jede Art von Datenlesefehlern. Und wenn es mehr Details eines Fehlers benötigt, kann es seine cause Eigenschaft überprüfen.,

Hier ist der Code, der definiert und seine Verwendung in readUser und try..catch:

Im obigen Code funktioniert readUser genau wie beschrieben – fängt Syntax-und Validierungsfehler ab und wirft stattdessen Fehler (unbekannte Fehler werden wie gewohnt neu gestürzt).

Der äußere Code überprüft also instanceof ReadError und das war ‚ s. Sie müssen nicht alle möglichen Fehlertypen auflisten.,

Der Ansatz heißt „wrapping exceptions“, weil wir“ low level „exceptions und“ wrap“sie in das ist abstrakter. Es ist in der objektorientierten Programmierung weit verbreitet.

Zusammenfassung

  • Wir können normalerweise von Error und anderen integrierten Fehlerklassen erben. Wir müssen uns nur um die Eigenschaft kümmern und nicht vergessen, superaufzurufen.
  • Wir können instanceof verwenden, um nach bestimmten Fehlern zu suchen. Es funktioniert auch mit Vererbung., Aber manchmal haben wir ein Fehlerobjekt, das aus einer Bibliothek eines Drittanbieters stammt, und es gibt keine einfache Möglichkeit, seine Klasse abzurufen. Dann name Eigenschaft kann für solche Prüfungen verwendet werden.
  • Das Umschließen von Ausnahmen ist eine weit verbreitete Technik: Eine Funktion behandelt Ausnahmen auf niedriger Ebene und erstellt Fehler auf höherer Ebene anstelle verschiedener Ausnahmen auf niedriger Ebene. Low-Level-Ausnahmen werden manchmal zu Eigenschaften dieses Objekts wie err.cause in den obigen Beispielen, aber das ist nicht unbedingt erforderlich.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.