Aktionen wie der Aufruf einer API oder die Validierung der vom Benutzer eingegebenen Daten kommen in der Entwicklung sehr häufig vor und sind Beispiele für Funktionen, die ein korrektes Ergebnis liefern oder fehlschlagen können. Im Allgemeinen verwenden und erstellen wir zur Steuerung in Javascript (und anderen Sprachen) einfache Ausnahmen.
Sie scheinen die einfachste Möglichkeit zu sein, Fehler zu kontrollieren, die in der Anwendung oder dem Programm, das wir entwickeln, auftreten können. Wenn Projekte und Teams jedoch wachsen, tauchen immer mehr Szenarien auf, die mehr von uns verlangen. In großen Teams ist es beispielsweise sehr hilfreich, wenn Funktionen explizit angeben, ob sie fehlschlagen können, damit unsere Kollegen diese Fehler antizipieren und bewältigen können.
Eine explizite Angabe der Arten von „Fehlern“, die eine Aktion haben kann, trägt nicht nur dazu bei, die Entwicklung viel einfacher zu machen. Es dient auch als Dokumentation der Geschäftsregeln.
In Javascript haben wir einige Techniken, um dies zu erreichen. Um über die Theorie hinauszugehen, betrachten wir ein Beispiel aus der Praxis: In einer Hotelbuchungs-App bucht ein Benutzer ein Zimmer, erhält einen Code und muss dann dafür bezahlen. Bei der Zahlung kann uns die API derzeit diese 3 „Fehler“-Szenarien anzeigen:
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Da wir einen Antrag für den Benutzer stellen, sollten Sie zusätzlich zu diesen beiden Fällen einen weiteren Fall berücksichtigen:
No hay conexión a internet. (o el servicio no esta disponible)
Diese Funktion kann von verschiedenen Komponenten unserer Anwendung aufgerufen werden und wenn sie fehlschlägt, muss der Fehler dem Benutzer angezeigt werden.
Lassen Sie uns anhand dieses Beispiels einige Möglichkeiten besprechen, wie man damit umgehen kann
Ausnahmen kommen in vielen Sprachen häufig vor und JavaScript enthält einige vordefinierte Ausnahmen (wie SyntaxError). Beim Umgang mit möglichen Fehlern empfiehlt es sich, konkret vorzugehen und sie zu personalisieren.
Um in js eine Ausnahme zu erstellen, verwenden Sie einfach das reservierte Wort throw gefolgt von dem, was wir wollen (wenn Sie es so lesen).
function makeError() { throw "Error string" }
Js ist in diesem Sinne sehr freizügig, es gilt jedoch als schlechte Praxis, etwas auszulösen, das nicht von der in js enthaltenen Error-Klasse abstammt.
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
Wie Sie sehen können, verfügt die Fehlerklasse über eine Eigenschaft, die es uns ermöglicht, detaillierter zu beschreiben, warum wir die Ausnahme erstellen (und wir können die gewünschten Eigenschaften hinzufügen).
Um auf das Problem zurückzukommen, das wir als Beispiel angeführt haben. Durch die Anwendung benutzerdefinierter Fehler können wir steuern, was in jedem Szenario zu tun ist.
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Damit erhalten wir nicht nur die Möglichkeit, den Fluss auf unterschiedliche Weise weiterzuleiten, sondern wir unterscheiden auch zwischen internen Fehlern des Systems (zum Beispiel dem Fehler einer internen Abhängigkeit, die wir in payReservation usw. verwenden) und den Geschäftsregeln .
Dies ist eine sehr gute Option und erfüllt unser Ziel, den Fluss individuell zu steuern. Wenn jemand die Funktion sieht, weiß er, warum sie fehlschlagen kann. Damit gewinnen wir bereits viel, allerdings gibt es einige Dinge, die wir bei diesem Ansatz beachten müssen.
Die Ausnahmen einer Funktion, wenn sie nicht innerhalb eines Catchs kontrolliert werden, gehen auf die „höhere Ebene“. Um ein Beispiel zu nennen: Wenn Sie die Funktion A haben, die B aufruft, ruft diese wiederum C auf und C löst eine Ausnahme aus . kontrolliert wird dies zu B gehen, wenn B es nicht kontrolliert, dann geht es weiter bis A usw. Abhängig von Ihrem Fall kann dies eine gute Nachricht sein. Das Deklarieren eines möglichen Fehlers durch eine Geschäftsregel könnte mühsam sein, da alle Funktionen auf mögliche Ausnahmen überprüft werden müssten.
Ein weiterer zu berücksichtigender Punkt ist der heute so geschätzte Entwicklerablauf. Obwohl Sie mit Tools wie JsDoc beschreiben können, dass eine Methode möglicherweise eine Ausnahme hat, erkennt der Editor diese nicht. Typescript hingegen erkennt diese Ausnahmen beim Schreiben oder Aufrufen der Funktion nicht.
[] **Leistung:* Das Auslösen und Behandeln von Ausnahmen hat einen (minimalen) Einfluss auf die Leistung (ähnlich wie die Verwendung von break). Obwohl in Umgebungen wie einer App diese Auswirkungen nahezu Null sind.
Wenn wir uns den vorherigen Fall ansehen, sind die von uns erstellten Ausnahmen nicht auf „irreparable“ Fehler zurückzuführen, sondern sind Teil der Geschäftsregeln. Wenn Ausnahmen häufig werden, sind sie keine wirklichen Ausnahmefälle mehr und wurden dafür konzipiert. Anstatt Ausnahmen auszulösen, können wir den Status „Erfolg“ und „Fehler“ wie folgt in einem einzelnen Objekt kapseln.
No hay conexión a internet. (o el servicio no esta disponible)
Wenn wir Typescript (oder d.ts, um jsdoc zu verwenden) verwenden, könnten wir die Typen wie folgt definieren.
function makeError() { throw "Error string" }
Anwenden auf unser Beispiel. Wenn unsere payReservation-Funktion nun dieses Objekt anstelle einer Ausnahme zurückgibt, können wir mithilfe von JSDoc oder Typescript angeben, welche Art von Ergebnissen wir verwenden können (von nun an werde ich der Einfachheit halber die Beispiele in Typescript einfügen).
Dadurch weiß das Team im Voraus, welche Fehler die Funktion möglicherweise zurückgibt.
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
Durch die Anwendung erhalten wir die Vorteile des Ansatzes mit Ausnahmen und außerdem zeigt der Editor zur Entwicklungszeit Informationen über die verschiedenen „Fehler“-Fälle an, die auftreten können.
Tatsächlich gibt es diese Art von Konzept in der Programmierung schon seit langem, in vielen funktionalen Sprachen gibt es keine Ausnahmen und sie verwenden diese Art von Daten für ihre Fehler, heute implementieren viele Sprachen sie. In Rust und Dart beispielsweise existiert die Result-Klasse nativ, Kotlins Arrow-Bibliothek fügt sie ebenfalls hinzu.
Es gibt einen bestimmten Standard für die Verwendung und Implementierung des Ergebnisses. Damit unser Code für neue Entwickler verständlicher ist, können wir uns auf diese Konventionen verlassen.
Das Ergebnis kann ausschließlich einen Erfolgs- oder Fehlerzustand darstellen (es kann nicht beides gleichzeitig sein) und ermöglicht das Arbeiten mit beiden Zuständen, ohne Ausnahmen auszulösen.
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Das Beispiel verwendet Klassen, aber das ist nicht notwendig, es gibt auch einfachere Implementierungen, ich habe eine, die ich normalerweise in Projekte mitnehme, bei denen ich denke, dass ich sie brauchen könnte, ich hinterlasse den Link für den Fall, dass Sie ihn sehen möchten und/oder Benutze es.
Wenn wir es so belassen, gewinnen wir in Bezug auf das Objekt, das wir zuvor erstellt haben, nicht viel. Deshalb ist es gut zu wissen, dass es normalerweise mehr Methoden implementiert
Zum Beispiel eine getOrElse-Methode, um im Fehlerfall Standardwerte zurückzugeben.
No hay conexión a internet. (o el servicio no esta disponible)
und falten, um den Erfolgs-/Misserfolgsfluss funktional zu handhaben.
function makeError() { throw "Error string" }
Möglicherweise finden Sie auch Informationen zur Fehlerbehandlung mit „Entweder“. Das Ergebnis wäre ein Entweder mit größerem Kontext. Entweder hat den Wert rechts (rechts) und links (links). Da right im Englischen auch verwendet wird, um zu sagen, dass etwas richtig ist, hat es normalerweise den richtigen Wert, während der Fehler auf der linken Seite steht, aber das ist nicht unbedingt der Fall, das Ergebnis ist stattdessen expliziter in Bezug auf wobei dies der korrekte Wert und der Fehler ist.
Angewandt auf unser Beispiel würde payReservation etwa so aussehen:
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
[*] Eine gute Vorgehensweise wäre die Einrichtung eines Basisdatentyps für Fehler, im Beispiel die Verwendung einer Zeichenfolge, aber idealerweise hätte er eine definiertere Form, wie etwa ein benanntes Objekt, zu dem weitere Daten hinzugefügt werden können. Beispiel: Ein Beispiel hierfür können Sie hier
sehenAuf den ersten Blick mag es scheinen, dass das Hinzufügen der Klasse mehr Over-Engineering ist als alles andere. Aber Ergebnis ist ein weit verbreitetes Konzept. Die Einhaltung von Konventionen hilft Ihrem Team, es schneller zu erfassen, und ist eine effektive Möglichkeit, Ihre Fehlerbehandlung zu verbessern.
Mit dieser Option beschreiben wir explizit, welche „Fehler“ eine Funktion haben kann, wir können den Ablauf unserer Anwendung entsprechend der Art des Fehlers steuern, wir erhalten beim Aufruf der Funktion Hilfe vom Editor und schließlich belassen wir Ausnahmen für Fehler Fälle im System.
Trotz dieser Vorteile müssen vor der Umsetzung auch einige Punkte berücksichtigt werden. Wie ich am Anfang dieses Abschnitts erwähnt habe, ist Result in vielen Sprachen nativ, jedoch nicht in JS. Daher fügen wir durch die Implementierung eine zusätzliche Abstraktion hinzu. Ein weiterer zu berücksichtigender Punkt ist das Szenario, in dem wir uns befinden. Nicht alle Anwendungen benötigen so viel Kontrolle (auf einer Zielseite einer Werbekampagne zum Beispiel würde ich keinen Sinn darin sehen, das Ergebnis zu implementieren). Es lohnt sich abzuwägen, ob Sie das gesamte Potenzial nutzen können oder es sich nur um zusätzliches Gewicht handelt.
Kurz gesagt verbessert der Umgang mit Fehlern nicht nur die Codequalität, sondern auch die Teamzusammenarbeit, indem er einen vorhersehbaren und gut dokumentierten Arbeitsablauf ermöglicht. Ergebnis- und benutzerdefinierte Ausnahmen sind Tools, die bei guter Verwendung zu besser wartbarem und robusterem Code beitragen.
In TypeScript können wir einen zusätzlichen Vorteil aus Result ziehen, um sicherzustellen, dass alle Fehlerfälle abgedeckt sind:
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
Die Funktion typeCheck zielt darauf ab, zu überprüfen, ob alle möglichen Werte von e innerhalb des if/else if überprüft werden.
In diesem Repo lasse ich etwas mehr Details.
Das obige ist der detaillierte Inhalt vonUmgang mit Fehlern in Javascript/Typescript: Benutzerdefinierte Ausnahmen und Ergebnisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!