Anpassen von Fehlern im Knoten.js

Javascript’s built in Error bietet nützliche Informationen, kann aber oft an Klarheit mangeln. One-Size-fits-all ist großartig für die Sprache, aber wir können es in unseren eigenen Apps besser machen. Hier kommen benutzerdefinierte Fehler ins Spiel.

Bei der Verwendung von Node sind möglicherweise benutzerdefinierte Fehler aufgetreten.js. Es gibt eingebaute Fehlertypen wie AssertionError, RangeError, ReferenceError, SyntaxError, und SystemError sind alle Erweiterungen der nativen Error -Klasse.

Wenn Sie Error als Basis verwenden, erhalten Sie die gesamte Leistung der Javascript-Implementierung sowie zusätzliche Vorteile. Hier sind nur einige:

  • Benutzerdefinierte Fehlermeldungsformate.
  • Zusätzliche Eigenschaften für das Fehlerobjekt.
  • Benannte Fehler, um das Debuggen und die bedingte Fehlerbehandlung zu vereinfachen.
  • Konsistente Fehler, auf die Bibliothekskonsumenten verweisen können.

Erweitern der Fehlerklasse

Lassen Sie uns zunächst ein generisches Beispiel verwenden. Wir werden die Error -Klasse erweitern und super verwenden, um ihre Funktionen zu erben.

class CustomError extends Error { constructor(...params) { super(...params) // We're spreading `params` as a way to bring all of `Error`'s functionality in. }}

Nun, wenn Sie throw einen Fehler, können Sie dies mit throw new CustomError("Something went wrong...") . Es gibt Ihnen auch die Möglichkeit, Fehler anhand des Typs zu überprüfen:

try { throw new CustomError("Something went wrong")} catch (error) { if (error instance of CustomError) { // do something specifically for that type of error }}

Dies allein macht nicht viel, außer Ihnen einen neuen Fehlertyp zu geben, den Sie anrufen und nach dem Sie suchen können. Um besser zu verstehen, was getan werden kann, schauen wir uns an, was auf Error Standard ist.

  • Error.name
  • Fehler.meldung
  • Fehler.Prototyp.toString()
  • Fehler.Prototyp.konstrukteur()

Gibt es nicht viel zu arbeiten? Abgesehen vom Konstruktor und der toString -Methode sind der Name des Fehlers und die Meldung, die den Fehler beschreibt, die einzigen Teile, die wir wahrscheinlich verwenden werden. Im obigen Beispiel wird message festgelegt, indem beim Instanziieren des Fehlers „Etwas ist schief gelaufen“ als Argument übergeben wird.

Glücklicherweise mögen die meisten Javascript-Plattformen den Browser und den Knoten.js haben ihre eigenen Methoden und Eigenschaften zu den aufgeführten hinzugefügt. Wir konzentrieren uns auf einige Aspekte der fehlerhaften Implementierung von V8, der Javascript-Engine, die Chrome und Node antreibt.js.

Die beiden Interessengebiete sind stack und captureStackTrace. Wie der Name schon sagt, können Sie den Stack-Trace anzeigen. Mal sehen, wie das an einem Beispiel aussieht.

class CustomError extends Error { constructor(...args) { super(...args) if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError) } this.name = "Our Custom Error" }}try { throw new CustomError("Something went wrong")} catch (err) { console.error(err.stack)}

In diesem Beispiel rufen wir Error.captureStackTrace auf, wenn die Plattform dies unterstützt, um sicherzustellen, dass unserem benutzerdefinierten Fehler ein vollständiger Trace hinzugefügt wird. Wir throw dann den Fehler aus dem try -Block, der die Kontrolle an den catch -Block weitergibt.

Wenn Sie den obigen Code ausführen, sehen Sie, dass die erste Zeile von stack die name und message des Fehlers ist.

Our Custom Error: Something went wrong

Dieser Fehler ist nicht sehr „tief“, daher besteht der Stapel hauptsächlich aus Knoten.js Interna. Jede Zeile ist ein „Frame“ des Stapels. Sie enthalten Details zum Ort des Fehlers innerhalb der Codebasis.

Nun, da wir wissen, wie man einen benutzerdefinierten Fehler erstellt und aufruft, machen wir ihn nützlich.

Fehlerinhalt anpassen

Der benutzerdefinierte Fehler, mit dem wir gearbeitet haben, ist in Ordnung, aber ändern wir ihn, um ihn nützlicher zu machen. Die Klasse wird CircuitError sein. Wir verwenden es, um benutzerdefinierte Fehler bereitzustellen, die von einem Leistungsschalter stammen. Wenn Sie mit dem Muster nicht vertraut sind, ist das in Ordnung. Die Implementierungsdetails des Leistungsschalters sind nicht wichtig. Wichtig ist, dass wir einige Informationen an den Fehler weitergeben können, und diese Informationen werden dem Benutzer angezeigt.

Ein Unterbrecher hat einen „OFFENEN“ Zustand, der für eine bestimmte Zeit nichts durchlässt. Lassen Sie uns unser CircuitError so einstellen, dass es einige Details enthält, die für die Funktionen nützlich sein können, die es empfangen, wenn der Status OPEN ist.

class CircuitError extends Error { // 1 constructor(state, nextAttempt, ...params) { super(...params) if (Error.captureStackTrace) { Error.captureStackTrace(this, CircuitError) } this.name = "CircuitError" this.state = state // 2 this.message = `The Circuit is ${state}.` // 3 if (nextAttempt) { this.timestamp = Date.now() this.nextAttempt = nextAttempt this.message += ` Next attempt can be made in ${this.nextAttempt - this.timestamp}ms.` } }}

Unser aktualisierter Fehler macht ein paar neue Dinge, alles innerhalb des Konstruktors. Die übergebenen Argumente haben sich geändert (1), um den state des Leistungsschalters sowie einen nextAttempt -Zeitstempel einzuschließen, der angibt, wann der Leistungsschalter erneut versucht, Anforderungen zu stellen.

Anschließend werden einige neue Eigenschaften festgelegt und die Nachricht in Abhängigkeit von den angezeigten Werten aktualisiert. Wir können es testen, indem wir eine neue Version dieses Fehlers auslösen.

try { throw new CircuitError("OPEN", Date.now() + 8000)} catch (err) { console.error(err)}

Wenn wir nun den Fehler auslösen, wird der Status als erstes Argument und ein Zeitstempel als zweites Argument verwendet. Für diese Demo vergehen wir 8000 Millisekunden in der Zukunft. Beachten Sie, dass wir auch den Fehler selbst protokollieren und nicht nur den Stapel.

Das Ausführen des Codes führt zu folgendem Ergebnis:

CircuitError : The Circuit is OPEN. Next attempt can be made in 6000ms. at Object.<anonymous> (/example.js:21:9) at Module._compile (internal/modules/cjs/loader.js:1063:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1103:10) at Module.load (internal/modules/cjs/loader.js:914:32) at Function.Module._load (internal/modules/cjs/loader.js:822:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1143:12) at internal/main/run_main_module.js:16:11 { name: 'Circuit Error', state: 'OPEN', message: 'The Circuit is OPEN. Next attempt can be made in 6000ms.', timestamp: 1580242308919, nextAttempt: 1580242314919}

Das Ergebnis ist der Fehlername, gefolgt von der Meldung in der ersten Zeile. Dann haben wir den Rest des Stapels, gefolgt von allen Eigenschaften, die wir in CircuitError festgelegt haben. Unsere Verbraucher dieses Fehlers könnten diese Daten verwenden, um auf den Fehler zu reagieren. Zum Beispiel:

try { throw new CircuitError("OPEN", Date.now() + 8000)} catch (err) { customLogger(err) if (err.state === "OPEN") { handleOpenState(err.nextAttempt) }}

Anstelle eines generischen Fehlers haben wir jetzt etwas, das den Anforderungen unserer Anwendung besser entspricht.

Reagieren auf Fehler

Benutzerdefinierte Fehler sind eine großartige Möglichkeit, auf Fehler zu reagieren. Es ist üblich anzunehmen, dass alle Fehler unerwartet sind, aber durch die Bereitstellung nützlicher Fehler können Sie ihre Existenz einfacher handhaben. Durch die Verwendung benutzerdefinierter Fehler können wir Benutzern unserer Anwendungen nicht nur wertvolle Daten zur Verfügung stellen, sondern auch die Möglichkeit bieten, über die Bedingung instance of auf Fehlertypen zu reagieren.

Bei Bearer verwenden wir benutzerdefinierte Fehler, um Antworten in unserem Code zu standardisieren, genau die Informationen bereitzustellen, die Sie in unserem Client benötigen, und unsere Fehler umsetzbar zu machen.

Wie verwenden Sie benutzerdefinierte Fehler in Ihren Anwendungen? Verbinden Sie sich mit uns @BearerSH und lassen Sie es uns wissen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.