Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.
In dieser Lektion kehren wir zum Thema Debugging von JavaScript zurück (das wir erstmalig in Was ist schiefgelaufen? betrachtet haben). Hier gehen wir tiefer auf Techniken zur Fehlerverfolgung ein und erklären, wie Sie defensiv programmieren und Fehler in Ihrem Code behandeln können, um Probleme von vornherein zu vermeiden.
| Ein Verständnis von HTML und den Grundlagen von CSS sowie Vertrautheit mit den JavaScript-Grundlagen, wie sie in früheren Lektionen behandelt wurden. |
|
Früher im Modul, in Was ist schiefgelaufen?, haben wir uns allgemein die Arten von Fehlern angesehen, die in JavaScript-Programmen auftreten können und gesagt, dass sie grob in zwei Typen unterteilt werden können — Syntaxfehler und Logikfehler. Wir haben Ihnen auch geholfen, einige häufige Arten von JavaScript-Fehlermeldungen zu verstehen, und gezeigt, wie Sie mit console.log() grundlegendes Debugging durchführen können.
In diesem Artikel werfen wir einen genaueren Blick auf die Werkzeuge, die zur Fehlerverfolgung zur Verfügung stehen, und betrachten auch Möglichkeiten, um Fehler von vornherein zu verhindern.
Sie sollten Ihren Code zuerst validieren, bevor Sie versuchen, spezifische Fehler zu finden. Nutzen Sie den Markup Validation Service, den CSS Validation Service der W3C und einen JavaScript-Linter wie ESLint, um sicherzustellen, dass Ihr Code gültig ist. Dies wird wahrscheinlich einige Fehler aufdecken, die Sie dann beheben können, sodass Sie sich auf die verbleibenden Fehler konzentrieren können.
Es ist nicht sehr praktisch, Ihren Code immer wieder in eine Webseite kopieren und einfügen zu müssen, um seine Gültigkeit zu überprüfen. Wir empfehlen, ein Linter-Plugin in Ihrem Code-Editor zu installieren, um Fehler direkt beim Schreiben des Codes zu melden. Versuchen Sie, in der Plugin- oder Erweiterungsliste Ihres Code-Editors nach ESLint zu suchen und es zu installieren.
Es gibt mehrere häufige JavaScript-Probleme, auf die Sie achten sollten, wie z.B.:
Zum Beispiel: In bad-for-loop.html (siehe Quellcode) durchlaufen wir 10 Iterationen mit einer mit var deklarierten Variablen, erstellen jedes Mal einen Paragraphen und fügen einen onclick-Ereignishandler hinzu. Beim Klicken soll jeder der Paragraphen eine Warnmeldung mit seiner Nummer anzeigen (dem Wert von i zur Erstellungszeit). Stattdessen berichten alle Paragraphen i als 11 — weil die for-Schleife alle Iterationen durchläuft, bevor verschachtelte Funktionen aufgerufen werden.
Die einfachste Lösung besteht darin, die Iterationsvariable mit let statt var zu deklarieren — der Wert von i, der der Funktion zugeordnet ist, ist dann für jede Iteration einzigartig. Siehe good-for-loop.html (sehen Sie auch den Quellcode an) für eine funktionierende Version.
Hinweis: Fehlerhafter JavaScript-Code: Die 10 häufigsten Fehler, die JavaScript-Entwickler machen bietet einige gute Diskussionsbeiträge zu diesen häufigen Fehlern und mehr.
Entwickler-Tools im Browser haben viele nützliche Funktionen zum Debuggen von JavaScript. Zum einen wird die JavaScript-Konsole Fehler in Ihrem Code melden.
Machen Sie eine lokale Kopie unseres fetch-broken-Beispiels (siehe auch den Quellcode).
Wenn Sie sich die Konsole ansehen, sehen Sie eine Fehlermeldung. Die genaue Wortwahl ist browserabhängig, aber sie wird ungefähr so lauten: "Uncaught TypeError: heroes is not iterable", und die referenzierte Zeilennummer ist 25. Wenn wir uns den Quellcode ansehen, lautet der relevante Abschnitt dieses:
Der Code stürzt also ab, sobald wir versuchen, jsonObj zu verwenden (was, wie Sie vielleicht erwarten, ein JSON-Objekt sein soll). Dies soll aus einer externen .json-Datei mit dem folgenden fetch()-Aufruf abgerufen werden:
Allerdings schlägt dies fehl.
Sie wissen vielleicht bereits, was mit diesem Code nicht stimmt, aber lassen Sie uns einen Blick werfen, wie Sie dies untersuchen könnten. Wir beginnen mit der Console-API, die es JavaScript-Code ermöglicht, mit der JavaScript-Konsole des Browsers zu interagieren. Sie bietet mehrere Funktionen; Sie sind bereits auf console.log() gestoßen, das eine benutzerdefinierte Nachricht in der Konsole ausgibt.
Versuchen Sie, einen console.log()-Aufruf hinzuzufügen, um den Rückgabewert von fetch() zu protokollieren, wie dies:
Aktualisieren Sie die Seite im Browser. Dieses Mal, vor der Fehlermeldung, sehen Sie eine neue Nachricht, die in die Konsole protokolliert wurde:
Response value: [object Promise]Die Ausgabe von console.log() zeigt, dass der Rückgabewert von fetch() nicht die JSON-Daten sind, sondern ein Promise. Die fetch()-Funktion ist asynchron: Sie gibt ein Promise zurück, das erst erfüllt wird, wenn die eigentliche Antwort aus dem Netzwerk eingegangen ist. Bevor wir die Antwort verwenden können, müssen wir warten, bis das Promise erfüllt ist.
Als kurzen Exkurs versuchen wir, eine andere Konsolenmethode zu verwenden, um den Fehler zu melden — console.error(). Ersetzen Sie in Ihrem Code:
durch
Speichern Sie Ihren Code und aktualisieren Sie den Browser; Sie werden nun sehen, dass die Meldung als Fehler gemeldet wird, mit derselben Farbe und demselben Symbol wie der nicht abgefangene Fehler darunter. Darüber hinaus werden Sie neben der Meldung einen Erweiterungs-/Reduzierpfeil sehen. Wenn Sie darauf drücken, sehen Sie eine einzelne Zeile, die die Zeile in der JavaScript-Datei angibt, in der der Fehler entstanden ist. Tatsächlich hat auch die Zeile des nicht abgefangenen Fehlers das, aber sie hat zwei Zeilen:
showHeroes http://localhost:7800/js-debug-test/index.js:25 <anonymous> http://localhost:7800/js-debug-test/index.js:10Das bedeutet, dass der Fehler durch die showHeroes()-Funktion auf Zeile 25 verursacht wird, wie wir bereits vorher erwähnt haben. Wenn Sie sich Ihren Code ansehen, werden Sie sehen, dass der anonyme Aufruf in Zeile 10 showHeroes() aufruft. Diese Zeilen werden als Aufrufstapel bezeichnet und können nützlich sein, wenn man versucht, die Quelle eines Fehlers zu finden, der mehrere verschiedene Positionen im Code betrifft.
Der console.error()-Aufruf ist in diesem Fall nicht besonders nützlich, kann jedoch nützlich sein, um einen Aufrufstapel zu generieren, wenn noch keiner verfügbar ist.
Lassen Sie uns sowieso zu unserem Fehler zurückkehren und versuchen, ihn zu beheben. Wir können auf die Antwort aus dem erfüllten Promise zugreifen, indem wir die then()-Methode an das Ende des fetch()-Aufrufs anhängen. Wir können dann den resultierenden Antwortwert in die Funktionen einfügen, die ihn akzeptieren, wie folgt:
Speichern und aktualisieren Sie die Datei, und sehen Sie, ob Ihr Code funktioniert. Spoiler-Alarm — die obige Änderung hat das Problem nicht behoben. Leider haben wir immer noch denselben Fehler!
Hinweis: Zusammengefasst: Jedes Mal, wenn etwas nicht funktioniert und ein Wert an einem bestimmten Punkt im Code nicht das zu sein scheint, was er sein sollte, können Sie console.log(), console.error() oder eine ähnliche Funktion verwenden, um den Wert auszugeben und zu sehen, was passiert.
Lassen Sie uns dieses Problem weiter untersuchen, indem wir eine ausgefeiltere Funktion der Entwickler-Tools des Browsers verwenden: den JavaScript-Debugger, wie er in Firefox genannt wird.
Hinweis: Ähnliche Tools sind in anderen Browsern verfügbar; der Sources-Tab in Chrome, Debugger in Safari (siehe Safari Web Development Tools) usw.
In Firefox sieht der Debugger-Tab so aus:
Die Hauptfunktion solcher Tools ist die Möglichkeit, Breakpoints im Code hinzuzufügen — das sind Punkte, an denen die Ausführung des Codes stoppt, und an diesem Punkt können Sie die Umgebung in ihrem aktuellen Zustand untersuchen und sehen, was vor sich geht.
Lassen Sie uns die Verwendung von Breakpoints erkunden:
Wir können einige sehr nützliche Informationen hier finden:
Das Argument der Funktion showHeroes() ist der Wert, mit dem das fetch()-Promise erfüllt wurde. Dieses Promise liegt nicht in JSON-Format vor: Es handelt sich um ein Response-Objekt. Es ist ein zusätzlicher Schritt erforderlich, um den Inhalt der Antwort als JSON-Objekt abzurufen.
Wir möchten, dass Sie versuchen, dieses Problem selbst zu beheben. Um Ihnen den Einstieg zu erleichtern, werfen Sie einen Blick in die Dokumentation des Response-Objekts. Wenn Sie nicht weiterkommen, finden Sie den korrigierten Quellcode unter https://github.com/mdn/learning-area/tree/main/tools-testing/cross-browser-testing/javascript/fetch-fixed.
Hinweis: Der Debugger-Tab hat viele andere nützliche Funktionen, die hier nicht behandelt werden. Zum Beispiel konditionale Breakpoints und Beobachtungsausdrücke. Für viele weitere Informationen, siehe die Debugger-Seite.
HTML und CSS sind tolerant — Fehler und nicht erkannte Funktionen können oft aufgrund der Natur der Sprachen gehandhabt werden. Zum Beispiel ignoriert CSS nicht erkannte Eigenschaften, und der restliche Code funktioniert oft einfach. JavaScript ist jedoch nicht so tolerant wie HTML und CSS; wenn die JavaScript-Engine auf Fehler oder unerkannten Syntax stößt, wirft sie oft Fehler.
Lassen Sie uns eine gängige Strategie zur Behandlung von JavaScript-Fehlern in Ihrem Code erkunden. Die folgenden Abschnitte sind so gestaltet, dass sie durch das Erstellen einer Kopie der unten gezeigten Vorlagendatei als handling-errors.html auf Ihrem lokalen Computer verfolgt werden, indem Sie die Codeschnipsel zwischen den öffnenden und schließenden <script> und </script>-Tags hinzufügen und dann die Datei in einem Browser öffnen und die Ausgabe in der JavaScript-Konsole der Entwickler-Tools betrachten.
Eine häufige Verwendung von JavaScript-Bedingungen besteht darin, Fehler zu behandeln. Bedingte Anweisungen ermöglichen es Ihnen, unterschiedlichen Code abhängig vom Wert einer Variable auszuführen. Oft möchten Sie dies defensiv verwenden, um zu vermeiden, dass ein Fehler ausgelöst wird, wenn der Wert nicht vorhanden ist oder nicht den richtigen Typ hat, oder um einen Fehler abzufangen, wenn der Wert ein falsches Ergebnis zurückgeben würde, was später zu Problemen führen könnte.
Schauen wir uns ein Beispiel an. Angenommen, wir haben eine Funktion, die die Körpergröße eines Benutzers in Zoll als Argument nimmt und seine Größe in Metern auf 2 Dezimalstellen genau zurückgibt. Dies könnte so aussehen:
Deklarieren Sie im <script>-Element Ihres Beispiels eine const namens height und weisen Sie ihr den Wert 70 zu:
Kopieren Sie die obige Funktion unter die vorherige Zeile.
Rufen Sie die Funktion auf, übergeben Sie der das height-Konstante als ihr Argument und protokollieren Sie den Rückgabewert in der Konsole:
Laden Sie das Beispiel in einem Browser und schauen Sie sich die JavaScript-Konsole der Entwickler-Tools an. Sie sollten einen Wert von 1.78 in der Konsole sehen.
Das funktioniert also ohne Probleme. Aber was passiert, wenn die bereitgestellten Daten fehlen oder falsch sind? Probieren Sie die folgenden Szenarien aus:
Offensichtlich sind diese Ergebnisse nicht optimal. Wie schützen wir uns gegen fehlerhafte Daten?
Lassen Sie uns eine Bedingung in unserer Funktion hinzufügen, um zu testen, ob die Daten gut sind, bevor wir versuchen, die Berechnung durchzuführen. Ersetzen Sie Ihre aktuelle Funktion durch folgende:
Wenn Sie jetzt die ersten zwei Szenarien erneut testen, sehen Sie unsere etwas nützlichere Nachricht, die Ihnen sagt, was zu tun ist, um das Problem zu beheben. Sie könnten dort alles hineinschreiben, was Sie möchten, einschließlich dem Versuch, Code zur Korrektur des num-Wertes auszuführen, aber dies wird nicht empfohlen — diese Funktion hat einen einfachen Zweck, und Sie sollten die Korrektur des Wertes irgendwo anders im System vornehmen.
Hinweis: Im if()-Statement testen wir zuerst, ob der Datentyp von num "number" ist, indem wir den typeof-Operator verwenden, und dann testen wir, ob Number.isNaN(num) false zurückgibt. Wir müssen dies tun, um sich gegen den spezifischen Fall von num als NaN zu verteidigen, da typeof NaN immer noch "number" zurückgibt!
Wenn Sie jedoch das dritte Szenario erneut testen, erhalten Sie immer noch die "Uncaught ReferenceError: height is not defined" Fehleranzeige. Sie können das Fehlen eines Wertes nicht innerhalb einer Funktion beheben, die versucht, den Wert zu verwenden.
Wie gehen wir damit um? Es ist besser, unsere Funktion dazu zu bringen, einen benutzerdefinierten Fehler zurückzugeben, wenn sie nicht die richtigen Daten erhält. Zuerst zeigen wir, wie das geht, und dann behandeln wir alle Fehler zusammen.
Sie können an jedem Punkt in Ihrem Code einen benutzerdefinierten Fehler mit der throw Anweisung in Verbindung mit dem Error() Konstruktor auslösen. Lassen Sie uns dies in Aktion sehen.
Ersetzen Sie in Ihrer Funktion die console.log()-Zeile innerhalb des else-Blocks durch folgende Zeile:
Führen Sie Ihr Beispiel erneut aus, aber stellen Sie sicher, dass num auf einen schlechten (d.h. nicht nummerischen) Wert gesetzt ist. Dieses Mal sollten Sie sehen, dass Ihr benutzerdefinierter Fehler ausgegeben wird, zusammen mit einem nützlichen Aufrufstapel, um Ihnen zu helfen, die Quelle des Fehlers zu finden (obwohl die Meldung immer noch sagt, dass der Fehler "uncaught" oder "unhandled" ist). Okay, Fehler sind zwar ärgerlich, aber das ist viel nützlicher, als die Funktion erfolgreich auszuführen und einen nicht nummerischen Wert zurückzugeben, der später Probleme verursachen könnte.
Wie gehen wir dann mit all diesen Fehlern um?
Die try...catch-Anweisung ist speziell dafür ausgelegt, Fehler zu behandeln. Sie hat die folgende Struktur:
Im try-Block versuchen Sie, etwas Code auszuführen. Wenn dieser Code ohne das Auftreten eines Fehlers ausgeführt wird, ist alles in Ordnung, und der catch-Block wird ignoriert. Wenn jedoch ein Fehler auftritt, wird der catch-Block ausgeführt, der Zugriff auf das Error-Objekt bietet, das den Fehler darstellt, und Sie können Code zur Behebung des Fehlers ausführen.
Lassen Sie uns try...catch in unserem Code verwenden.
Ersetzen Sie die console.log()-Zeile, die die Funktion inchesToMeters() am Ende Ihres Skripts aufruft, durch den folgenden Block. Wir führen jetzt unsere console.log()-Zeile innerhalb eines try-Blocks aus und behandeln alle damit zurückgegebenen Fehler in einem entsprechenden catch-Block.
Speichern und aktualisieren Sie die Seite, und Sie sollten nun zwei Dinge sehen:
Versuchen Sie nun, num auf einen gültigen (nummerischen) Wert zu ändern, und Sie werden das Ergebnis der Berechnung protokolliert sehen, ohne Fehlermeldung.
Dies ist von Bedeutung — alle geworfenen Fehler werden jetzt behandelt, sodass sie die Anwendung nicht zum Absturz bringen. Sie können jeden beliebigen Code ausführen, um den Fehler zu behandeln. Oben protokollieren wir eine grundlegende Nachricht, aber Sie könnten zum Beispiel die Funktion aufrufen, die den Benutzer erneut nach seiner Größe fragt, aber dieses Mal bitten, den Eingabefehler zu korrigieren. Sie könnten sogar eine if...else-Anweisung verwenden, um je nach Fehlercode unterschiedliche Fehlerbehandlungscodes auszuführen.
Die Funktionsdetektion ist nützlich, wenn Sie planen, neue JavaScript-Features zu verwenden, die möglicherweise nicht in allen Browsern unterstützt werden. Sie können die Funktion testen und dann bedingt Code ausführen, um ein akzeptables Erlebnis in Browsern zu bieten, die die Funktion unterstützen, und in solchen, die es nicht tun. Als kurzes Beispiel hat die Geolocation API (die verfügbare Standortdaten für das Gerät bereitstellt, auf dem der Webbrowser läuft) einen Haupteinstiegspunkt für die Nutzung — eine geolocation-Eigenschaft, die auf dem globalen Navigator-Objekt verfügbar ist. Somit können Sie testen, ob der Browser Geolocation unterstützt, indem Sie eine ähnliche if()-Struktur verwenden, wie wir sie früher gesehen haben:
Sie finden einige weitere Beispiele für Funktionsdetektion in Alternativen zur UA-Erkennung.
Es gibt viele andere Probleme, auf die Sie mit JavaScript (und HTML und CSS!) stoßen werden, sodass Kenntnisse darüber, wie man Antworten online findet, von unschätzbarem Wert sind.
Zu den besten Quellen für Unterstützungsinformationen gehören MDN, stackoverflow.com und caniuse.com.
Abgesehen davon: Versuchen Sie, mit Ihrer bevorzugten Suchmaschine nach einer Antwort auf Ihr Problem zu suchen. Es ist oft hilfreich, nach spezifischen Fehlermeldungen zu suchen, wenn Sie diese haben — andere Entwickler werden wahrscheinlich die gleichen Probleme wie Sie gehabt haben.
Das war also JavaScript-Debugging und Fehlerbehandlung. Einfach, oder? Vielleicht nicht so einfach, aber dieser Artikel sollte Ihnen zumindest einen Anfang und einige Ideen geben, wie Sie mit JavaScript-bezogenen Problemen umgehen können, denen Sie begegnen werden.
Das war's für das Modul "Dynamisches Scripting mit JavaScript"; herzlichen Glückwunsch, dass Sie das Ende erreicht haben! Im nächsten Modul helfen wir Ihnen, JavaScript-Frameworks und -Bibliotheken zu erkunden.
Der Bauplan für ein besseres Internet.
Besuche die gemeinnützige Muttergesellschaft der Mozilla Corporation, die Mozilla Foundation.
Teile dieses Inhalts sind ©1998–2026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfügbar unter einer Creative-Commons-Lizenz.