Unabhängig von Ihrer Qualifikation sind Fehler oder Ausnahmen Teil des Lebens Ihres Anwendungsentwicklers. Die Inkonsistenz der Webentwicklung lässt viele Orte zurück, an denen Fehler aufgetreten sind und sind. Der Schlüssel zur Lösung liegt darin, mit unvorhergesehenen (oder vorhersehbaren Fehlern) umzugehen, um die Erfahrung des Benutzers zu steuern. Bei JavaScript gibt es eine Vielzahl von technischen und sprachlichen Funktionen, mit denen jedes Problem korrekt gelöst werden kann.
Es ist gefährlich, Fehler in JavaScript zu behandeln. Wenn Sie an Murphys Gesetz glauben, wird das schief gehen, was schief geht! In diesem Artikel werde ich in JavaScript in die Fehlerbehandlung eingehen. Ich werde einige Fallstricke und gute Praktiken einbeziehen. Schließlich werden wir die asynchrone Codeverarbeitung und Ajax besprechen.
Ich denke, das ereignisgesteuerte Modell von JavaScript verleiht dieser Sprache eine umfangreiche Bedeutung. Ich denke, es gibt keinen Unterschied zwischen dem ereignisorientierten Motor und dem Fehlermechanismus dieser Art von Browser. Immer wenn ein Fehler auftritt, ist es gleichwertig, ein Ereignis zu einem bestimmten Zeitpunkt zu werfen. Theoretisch können wir Fehler mit Fehler verarbeiten, die Ereignisse in JavaScript veröffentlichen, wie wir mit gewöhnlichen Ereignissen umgehen. Wenn Ihnen das seltsam klingt, konzentrieren Sie sich darauf, die folgende Reise zu beginnen. Dieser Artikel zielt nur auf das JavaScript des Kunden ab.
Beispiel
Die in diesem Artikel verwendeten Codebeispiele können auf GitHub erhalten werden. Die aktuelle Seite sieht so aus:
Durch Klicken auf jede Schaltfläche macht ein Fehler. Es simuliert die Ausnahme des TypeError -Typs. Das Folgende ist die Definition und der Unit -Test eines solchen Moduls.
Funktion error () {var foo = {}; return foo.bar ();}Zunächst definiert diese Funktion ein leeres Objekt foo. Beachten Sie, dass die bar () -Methode nirgendwo definiert ist. Wir verwenden Unit -Tests, um zu überprüfen, ob dies einen Fehler macht.
IT ('wirft ein TypenError aus', function () {sollte.tums (Ziel, typeerrror);});In diesem Unit -Test werden Testbehauptungen aus der Mokka verwendet und sollten.js -Bibliotheken. Mokka ist ein laufendes Testframework und sollte.js eine Assertion -Bibliothek. Wenn Sie mit ihnen nicht sehr vertraut sind, können Sie ihre Dokumente kostenlos online durchsuchen. Ein Testfall beginnt normalerweise damit ('Beschreibung') und endet mit dem Übergang oder dem Ausfall der Behauptung in sollte. Der Vorteil der Verwendung dieses Frameworks besteht darin, dass es nicht im Knoten und im Browser getestet werden kann. Ich schlage vor, Sie nehmen diese Tests ernst, weil sie viele wichtige grundlegende Konzepte in JavaScript validieren.
Wie oben gezeigt, definiert ERROR () ein leeres Objekt und versucht dann, die darin enthaltene Methode aufzurufen. Da die bar () -Methode in diesem Objekt nicht vorhanden ist, wird eine Ausnahme ausgelöst. Vertrauen Sie mir, in dynamischen Sprachen wie JavaScript kann jeder solche Fehler machen.
Schlechte Demonstration
Schauen wir uns die schlechten Fehlerbehandlungsmethoden an. Ich werde die falsche Aktion abstrahieren und sie an den Knopf binden. So sieht der Unit -Test des Handlers aus:
Funktion badhandler (fn) {try {return fn (); } catch (e) {} return null;}Diese Verarbeitungsfunktion empfängt eine Rückruffunktion FN als Abhängigkeit. Dann wird die Funktion im Handler aufgerufen. Diese Unit -Testbeispiele, wie diese Methode verwendet wird.
IT ('zurückgibt einen Wert ohne Fehler', function () {var fn = function () {return 1;}; var result = target (fn); result. sollte.equal (1);}); IT ('zurückgibt ein null mit fehlern', function () {var fn = function () {Wurf -Fehler ('randomer Fehler');};};};};};}; sollte (Ergebnis) .Equal (null);});Wie Sie sehen können, gibt diese seltsame Art des Umgangs mit einem Fehler ein Null zurück. Diese Rückruffunktion fn () verweist auf eine rechtliche Methode oder einen Fehler. Das folgende Klickenereignis folgt den Rest.
(Funktion (Handler, Bombe) {var badbutton = document.getElementById ('bad'); if (badbutton) {badbutton.adDeVent -Veristener ('click', function () {Handler (bomb); console.log ('vorstellbar, für die Verfeinerung von Fehlern beworben werden');Das Schlechte ist, dass das, was ich gerade bekommen habe, ein Null war. Dies machte mich sehr verwirrt, als ich darüber nachdachte, zu bestimmen, was falsch war. Diese Strategie des Schweigens, wenn Fehler auftreten, deckt jeden Link von der Benutzererfahrungsdesign bis zur Datenbeschädigung ab. Die frustrierende Seite folgte, dass ich Stunden damit verbringen musste, den Fehler im Versuchs-Code-Block nicht zu sehen. Diese seltsame Verarbeitung verbirgt alle Fehler im Code und wird davon ausgegangen, dass alles normal ist. Dies kann in einigen Teams, die nicht auf die Codequalität achten, reibungslos ausgeführt werden. Diese versteckten Fehler zwingen Sie jedoch schließlich, Stunden damit zu verbringen, Ihren Code zu debuggen. In einer mehrschichtigen Lösung, die sich auf dem Anrufstapel stützt, ist es möglich zu bestimmen, woher der Fehler stammt. Es kann angebracht sein, in seltenen Fällen die Try-Catch stillschweigend zu behandeln. Wenn Sie jedoch auf einen Fehler stoßen, werden Sie damit umgehen, was keine gute Lösung ist.
Dieses Versagen-die Stillestrategie wird Sie dazu veranlassen, mit Fehlern in Ihrem Code besser umzugehen. JavaScript bietet eine elegantere Möglichkeit, mit dieser Art von Problem umzugehen.
Keine lesbare Lösung
Lassen Sie uns weiterhin einen Blick auf den schwer verständlichen Ansatz werfen. Ich werde den eng gekoppelten Teil mit dem DOM überspringen. Dieser Teil unterscheidet sich nicht von dem schlechten Ansatz, den wir gerade gesehen haben. Der Fokus liegt auf der folgenden Einheitstests, die Ausnahmen behandelt.
Funktion UglyHandler (fn) {try {return fn (); } catch (e) {Wurf error ('ein neuer Fehler'); }} it ('gibt einen neuen Fehler mit fehlern zurück', function () {var fn = function () {neue typeerror werfen ('Typ error');}; Sollt.Thows (function () {target (fn);}, error);});Es gibt eine gute Verbesserung im Vergleich zur schlechten Behandlung gerade jetzt. Die Ausnahme wird in den Anrufstapel geworfen. Was ich mag, ist, dass die Fehler vom Stapel befreit werden, was für das Debuggen äußerst hilfreich ist. Wenn eine Ausnahme ausgelöst wird, wird der Dolmetscher die nächste Verarbeitungsfunktion auf einer Ebene im Anrufstapel betrachtet. Dies bietet viele Möglichkeiten, Fehler auf der oberen Ebene des Anrufstacks zu bewältigen. Da er ein schwieriger Fehler ist, kann ich die ursprünglichen Fehlerinformationen leider nicht sehen. Deshalb muss ich den Anrufstapel mitschauen und die primitivste Ausnahme finden. Aber zumindest weiß ich, dass ein Fehler auftritt, bei dem die Ausnahme ausgelöst wird.
Obwohl diese unlesbare Fehlerbehandlung harmlos ist, erschwert er den Code schwer zu verstehen. Mal sehen, wie der Browser Fehler umgeht.
Rufen Sie Stack an
Eine Möglichkeit, eine Ausnahme auszulösen, besteht darin, einen Versuch hinzuzufügen ... Catch Code -Block auf der oberen Ebene des Anrufstacks. Zum Beispiel:
Funktion main (bomb) {try {bomb (); } catch (e) {// ALLE ERFAHREN AUSGABEN}}}}}}}}}}}}}}}}}Aber erinnere dich, dass ich sagte, dass Browser ereignisorientiert sind? Ja, eine Ausnahme in JavaScript ist nichts anderes als ein Ereignis. Der Dolmetscher stoppt das Programm im Kontext, in dem derzeit die Ausnahme auftritt, und bringt eine Ausnahme aus. Um dies zu bestätigen, ist das Folgende eine globale Ereignisbearbeitungsfunktion OnError, die wir sehen können. Es sieht so aus:
window.adDeVentListener ('Fehler', Funktion (e) {var error = e.Error; console.log (error);});Dieser Event -Handler fängt Fehler in der Ausführungsumgebung auf. Fehlerereignisse erzeugen verschiedene Fehler an verschiedenen Stellen. Der Punkt dieses Ansatzes besteht darin, fehler im Code zentral umzugehen. Genau wie bei anderen Ereignissen können Sie einen globalen Handler verwenden, um verschiedene Fehler zu behandeln. Dies macht Fehler nur zu einem einzigen Ziel, wenn Sie sich an die festen (einzelnen Verantwortung, offenen Liskov-Substitution, Grenzflächensegregation und Abhängigkeitsinversion) halten. Sie können jederzeit Fehlerbehandlungsfunktionen registrieren. Der Interpreter führt diese Funktionsschleifen aus. Der Code wird von Aussagen mit dem Versuch befreit ... Fang und leicht zu debuggen. Der Schlüssel zu diesem Ansatz liegt darin, Fehler zu behandeln, die genau wie normale JavaScript -Ereignisse auftreten.
Jetzt gibt es eine Möglichkeit, den Anrufstapel mit einer globalen Verarbeitungsfunktion anzuzeigen. Was können wir damit machen? Schließlich müssen wir den Anrufstapel verwenden.
Notieren Sie den Anrufstapel
Der Anrufstack ist sehr nützlich bei der Behandlung von Fehlerbehebungen. Die gute Nachricht ist, dass der Browser diese Informationen bereitstellt. Obwohl das Stapelattribut des Fehlerobjekts derzeit nicht Standard ist, wird dieses Attribut im Allgemeinen in neueren Browsern unterstützt.
Das Coole, was wir tun können, ist, es auf den Server auszudrucken:
window.addEventListener('error', function (e) { var stack = e.error.stack; var message = e.error.toString(); if (stack) { message += '/n' + stack; } var xhr = new XMLHttpRequest(); xhr.open('POST', '/log', true); xhr.send(message);});Im Code -Beispiel ist dies möglicherweise nicht offensichtlich, aber dieser Ereignishandler wird durch den vorherigen Fehlercode ausgelöst. Wie oben erwähnt, hat jeder Handler einen einzelnen Zweck, der den Code trocken macht (wiederholt sich nicht wiederholt das Rad). Ich interessiere mich, um diese Nachrichten auf dem Server zu erfassen.
Hier ist ein Screenshot der Knoten -Laufzeit:
Der Anrufstack ist sehr hilfreich, um den Code zu debuggen. Unterschätzen Sie niemals die Rolle des Anrufstacks.
Asynchrone Verarbeitung
Oh, es ist ziemlich gefährlich, mit asynchronem Code umzugehen! JavaScript bringt asynchrone Code aus der aktuellen Ausführungsumgebung heraus. Dies bedeutet, dass es ein Problem mit dem Versuch gibt ... eine Erklärung der folgenden Erklärung.
Funktion Asynchandler (fn) {try {setTimeout (function () {fn ();}, 1); } catch (e) {}}Es gibt noch einen Teil dieses Unit -Tests:
IT ('fängt keine Ausnahmen mit Fehlern ab', function () {var fn = function () {typeerror werfen ('Typ error');}; failEdPromise (function () {target (fn);}). sollte.be.Rejeced With (TypeError);}); });}Ich muss diesen Handler mit dem Versprechen beenden, die Ausnahme zu überprüfen. Beachten Sie, dass mein Code zwar alles im Versuch ist ... Catch, eine ungehandelte Ausnahme erscheint immer noch. Ja, versuchen Sie ... nur in einer separaten Ausführungsumgebung zu fangen. Wenn die Ausnahme ausgelöst wird, ist die Ausführungsumgebung des Interpreters nicht mehr der aktuelle Try-Catch-Block. Dieses Verhalten tritt ähnlich wie bei Ajax -Aufrufen auf. Jetzt gibt es also zwei Optionen. Eine Alternative besteht darin, Ausnahmen in einem asynchronen Rückruf zu fangen:
setTimeout (function () {try {fn ();} catch (e) {// Behandle diesen asynchrischen Fehler}}, 1);Obwohl diese Methode nützlich ist, gibt es immer noch viel Raum für Verbesserungen. Versuchen Sie zunächst ... Catch -Codeblöcke erscheinen überall im Code. In den 1970er Jahren wollten sie in den 1970er Jahren zurückfallen. Darüber hinaus entmutigt die V8 -Engine die Verwendung von Versuch… Catch -Codeblöcke in Funktionen (V8 ist die JavaScript -Engine, die von Chrome Browser und Knoten verwendet wird). Sie empfehlen, diese Codeblöcke zu schreiben, die Ausnahmen oben im Anrufstapel fangen.
Also, was sagt uns das? Wie ich oben sagte, sind globale Fehlerhandler in einem beliebigen Ausführungskontext erforderlich. Wenn Sie einem Fensterobjekt einen Fehlerhandler hinzufügen, sind Sie fertig! Ist es nicht schön, den Prinzipien von Trocken und Festen zu folgen? Ein globaler Fehlerhandler hält Ihren Code lesbar und sauber.
Das Folgende ist der Bericht, der auf der serverseitigen Ausnahmebehandlung gedruckt wird. Beachten Sie, dass die Ausgabe, wenn Sie den Code im Beispiel verwenden, je nach dem von Ihnen verwendeten Browser geringfügig variieren kann.
Dieser Handler kann mir sogar sagen, welcher Fehler aus asynchronem Code stammt. Es sagt mir, dass der Fehler aus dem SetTimeout () -Handler stammt. So cool!
Fehler sind Teil jeder Anwendung, die korrekte Fehlerbehandlung jedoch nicht. Es gibt mindestens zwei Möglichkeiten, mit Fehlern umzugehen. Eine davon ist eine Lösung des Versagens, der Stille, dh Fehler im Code. Eine andere Möglichkeit besteht darin, Fehler schnell zu erkennen und zu lösen, d. H. Auf dem Fehler stoppen und sich reproduzieren. Ich glaube, ich habe klar ausgedrückt, was ich mag und warum ich es mag. Meine Wahl: Verstecke das Problem nicht. Niemand wird Ihnen die Schuld für unerwartete Ereignisse in Ihrem Programm beschuldigen. Dies ist akzeptabel, um Punkte zu brechen, sich zu reproduzieren und den Benutzer auszuprobieren. In einer unvollkommenen Welt ist es wichtig, sich eine Chance zu geben. Fehler sind unvermeidlich, und was Sie tun, ist wichtig, um den Fehler zu lösen. Die angemessene Verwendung der Fehlerbehandlungsfunktionen von JavaScript und automatischer und flexibler Dekodierung kann die Erfahrung des Benutzers reibungsloser und die Diagnose des Entwicklers erleichtern.