Debugging von JavaScript und Fehlerbehandlung
Hinweis: Der Inhalt dieses Artikels ist derzeit unvollständig, tut uns leid! Wir arbeiten hart daran, den Abschnitt "MDN Learn Web Development" zu verbessern, und werden bald die als unvollständig ("TODO") markierten Stellen fertigstellen.
In dieser Lektion kehren wir zum Thema Debugging von JavaScript zurück (das wir zuerst in Was ist schiefgelaufen? betrachtet haben). Hier werden wir tiefer in Techniken zur Fehlersuche eintauchen und uns außerdem ansehen, wie Sie defensiv programmieren und Fehler in Ihrem Code behandeln können, um von vornherein Probleme zu vermeiden.
Voraussetzungen: | Ein Verständnis von HTML und den Grundlagen von CSS, Vertrautheit mit den JavaScript-Grundlagen, wie sie in den vorherigen Lektionen behandelt wurden. |
---|---|
Lernziele: |
|
Rückblick auf Arten von JavaScript-Fehlern
Früher im Modul, in Was ist schiefgelaufen?, haben wir die Arten von Fehlern betrachtet, 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 einfaches Debugging mithilfe von console.log()
-Anweisungen durchführen können.
In diesem Artikel werden wir ein wenig tiefer in die Tools eintauchen, die Ihnen zur Verfügung stehen, um Fehler aufzuspüren, und uns auch Möglichkeiten ansehen, um Fehler von vornherein zu verhindern.
Ihr Code muss gültig sein
Sie sollten sicherstellen, dass Ihr Code gültig ist, bevor Sie versuchen, spezifische Fehler aufzuspüren. Nutzen Sie den Markup-Validierungsdienst der W3C, den CSS-Validierungsdienst und einen JavaScript-Linter wie ESLint, um sicherzustellen, dass Ihr Code gültig ist. Dies wird wahrscheinlich eine Reihe von Fehlern aufdecken und es Ihnen ermöglichen, sich auf die verbleibenden Fehler zu konzentrieren.
Code-Editor-Plugins
Es ist nicht sehr praktisch, Ihren Code immer wieder auf eine Webseite zu kopieren und einzufügen, um dessen Gültigkeit zu überprüfen. Wir empfehlen Ihnen, ein Linter-Plugin in Ihrem Code-Editor zu installieren, damit Ihnen Fehler angezeigt werden, während Sie Ihren Code schreiben. Versuchen Sie, in der Plugin- oder Erweiterungsliste Ihres Code-Editors nach ESLint zu suchen und es zu installieren.
Häufige JavaScript-Probleme
Es gibt eine Reihe häufiger JavaScript-Probleme, auf die Sie achten sollten, wie zum Beispiel:
- Grundlegende Syntax- und Logikprobleme (siehe erneut Problemlösung bei JavaScript).
- Stellen Sie sicher, dass Variablen usw. im richtigen Scope definiert sind und dass Sie keine Konflikte zwischen Elementen haben, die an verschiedenen Stellen deklariert sind (siehe Funktions-Scope und Konflikte).
- Verwechslung von this, im Hinblick darauf, auf welchen Scope es sich bezieht, und ob sein Wert daher das ist, was Sie beabsichtigt haben. Sie können Was ist "this"? für eine leichte Einführung lesen; Sie sollten sich auch Beispiele wie dieses hier ansehen, das ein typisches Muster zeigt, in dem ein
this
-Scope in einer separaten Variablen gespeichert wird, um sicherzustellen, dass Sie die Funktionalität auf den richtigenthis
-Scope anwenden. - Das fehlerhafte Verwenden von Funktionen innerhalb von Schleifen, die mit einer globalen Variablen iterieren (allgemeiner "das falsche Scope bekommen").
Beispielsweise in bad-for-loop.html (siehe den Quellcode), durchlaufen wir 10 Iterationen unter Verwendung einer mit var
definierten Variablen, erstellen jedes Mal einen Absatz und fügen ihm einen onclick-Ereignishandler hinzu. Beim Klicken möchten wir, dass jeder eine Alert-Nachricht mit seiner Nummer anzeigt (dem Wert von i
zum Zeitpunkt seiner Erstellung). Stattdessen melden alle i
als 11 – weil die for
-Schleife alle ihre Iterationen durchführt, bevor verschachtelte Funktionen aufgerufen werden.
Die einfachste Lösung besteht darin, die Iterationsvariable mit let
anstelle von var
zu deklarieren – der Wert von i
, der mit der Funktion verknüpft ist, ist dann einzigartig für jede Iteration. Siehe good-for-loop.html (siehe auch den Quellcode) für eine funktionierende Version.
- Sicherstellen, dass asynchrone Operationen abgeschlossen sind, bevor versucht wird, die von ihnen zurückgegebenen Werte zu verwenden. Dies bedeutet normalerweise, dass Sie verstehen müssen, wie man Promises verwendet: das Verwenden von
await
in geeigneter Weise oder das Ausführen des Codes zur Behandlung des Ergebnisses eines asynchronen Aufrufs imthen()
-Handler des Promises. Siehe Wie man Promises verwendet für eine Einführung in dieses Thema.
Hinweis: Fehlerhafter JavaScript-Code: Die 10 häufigsten Fehler, die JavaScript-Entwickler machen bietet einige nette Diskussionen über diese häufigen Fehler und mehr.
Die JavaScript-Konsole des Browsers
Die Entwickler-Tools des Browsers haben viele nützliche Funktionen, die beim Debuggen von JavaScript helfen können. Zunächst einmal 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 Formulierung hängt vom Browser ab, aber sie wird etwa folgendermaßen lauten: "Uncaught TypeError: heroes is not iterable", und die referenzierte Zeilennummer ist 25. Wenn wir uns den Quellcode ansehen, ist der relevante Codeabschnitt dieser:
function showHeroes(jsonObj) {
const heroes = jsonObj["members"];
for (const hero of heroes) {
// ...
}
}
Also stürzt der Code ab, sobald wir versuchen, jsonObj
zu verwenden (das, wie Sie vielleicht erwarten, ein JSON-Objekt sein soll). Dies soll von einer externen .json
-Datei mit dem folgenden fetch()
-Aufruf abgerufen werden:
const requestURL =
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
const response = fetch(requestURL);
populateHeader(response);
showHeroes(response);
Aber das schlägt fehl.
Die Console-API
Vielleicht wissen Sie bereits, was mit diesem Code nicht stimmt, aber lassen Sie uns das etwas genauer untersuchen, um zu zeigen, 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 hat eine Reihe von Funktionen zur Verfügung; 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, etwa so:
const requestURL =
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
const response = fetch(requestURL);
console.log(`Response value: ${response}`);
const superHeroes = response;
populateHeader(superHeroes);
showHeroes(superHeroes);
Aktualisieren Sie die Seite im Browser. Dieses Mal, vor der Fehlermeldung, sehen Sie eine neue Nachricht in der Konsole protokolliert:
Response value: [object Promise]
Die console.log()
-Ausgabe zeigt, dass der Rückgabewert von fetch()
nicht die JSON-Daten ist, sondern ein Promise
. Die fetch()
-Funktion ist asynchron: Sie gibt ein Promise
zurück, das nur erfüllt wird, sobald die eigentliche Antwort vom Netzwerk empfangen wurde. Bevor wir die Antwort verwenden können, müssen wir warten, bis das Promise
erfüllt ist.
Wir können dies erreichen, indem wir den Code, der die Antwort verwendet, in die then()
-Methode des zurückgegebenen Promise
einfügen, etwa so:
fetch(requestURL).then((response) => {
populateHeader(response);
showHeroes(response);
});
Zusammenfassend: Jedes Mal, wenn etwas nicht funktioniert und ein Wert an einem bestimmten Punkt in Ihrem Code nicht so zu sein scheint, wie er sein sollte, können Sie console.log()
verwenden, um ihn auszugeben und zu sehen, was geschieht.
Verwendung des JavaScript-Debuggers
Leider haben wir immer noch denselben Fehler – das Problem ist nicht verschwunden. Untersuchen wir dies nun, mit einem anspruchsvolleren Feature der Entwickler-Tools des Browsers: dem JavaScript-Debugger, wie er in Firefox genannt wird.
Hinweis: Ähnliche Werkzeuge 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:
- Auf der linken Seite können Sie das Skript auswählen, das Sie debuggen möchten (in diesem Fall haben wir nur eines).
- Das mittlere Panel zeigt den Code im ausgewählten Skript.
- Das rechte Panel zeigt nützliche Details zur aktuellen Umgebung — Breakpoints, Callstack und aktuell aktive Scopes.
Die Hauptfunktion solcher Werkzeuge besteht darin, Breakpoints in den Code einzufü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 an die Arbeit gehen. Der Fehler wird jetzt in Zeile 26 geworfen. Klicken Sie im mittleren Panel auf Zeile 26, um dort einen Breakpoint hinzuzufügen (Sie sehen einen blauen Pfeil darüber erscheinen). Aktualisieren Sie nun die Seite (Cmd/Ctrl + R) — der Browser wird die Ausführung des Codes in Zeile 26 anhalten. An diesem Punkt wird die rechte Seite aktualisiert, um einige sehr nützliche Informationen anzuzeigen.
- Unter Breakpoints sehen Sie die Details des gesetzten Breakpoints.
- Unter Call Stack sehen Sie ein paar Einträge – dies ist im Grunde eine Liste der Abfolge von Funktionen, die aufgerufen wurden, um die aktuelle Funktion aufzurufen. Ganz oben haben wir
showHeroes()
, die Funktion, in der wir uns derzeit befinden, und als zweites haben wironload
, die die Ereignishandler-Funktion speichert, die den Aufruf zushowHeroes()
enthält. - Unter Scopes sehen Sie den aktuell aktiven Scope für die Funktion, die wir betrachten. Wir haben nur drei —
showHeroes
,block
, undWindow
(der globale Scope). Jeder Scope kann erweitert werden, um die Werte der Variablen im Scope zu dem Zeitpunkt anzuzeigen, an dem die Ausführung des Codes angehalten wurde.
Hierin können wir einige sehr nützliche Informationen finden.
- Erweitern Sie den
showHeroes
Scope — Sie können daraus erkennen, dass die heroes-Variableundefined
ist, was darauf hindeutet, dass der Zugriff auf diemembers
-Eigenschaft vonjsonObj
(erste Zeile der Funktion) nicht funktioniert hat. - Sie können auch sehen, dass die
jsonObj
-Variable einResponse
-Objekt speichert, nicht ein JSON-Objekt.
Das Argument für showHeroes()
ist der Wert, mit dem das fetch()
-Promise erfüllt wurde. Dieses Promise liegt also nicht im JSON-Format vor: es ist ein Response
-Objekt. Es gibt einen zusätzlichen Schritt, der erforderlich ist, 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, sehen Sie sich die Dokumentation für das Response
-Objekt an. Falls Sie stecken bleiben, 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 wir hier nicht besprochen haben, zum Beispiel bedingte Breakpoints und Watch-Expressions. Für viele weitere Informationen siehe die Debugger-Seite.
Umgang mit JavaScript-Fehlern in Ihrem Code
HTML und CSS sind nachgiebig — Fehler und nicht erkannte Features können oft aufgrund der Natur der Sprachen gehandhabt werden. Zum Beispiel ignoriert CSS nicht erkannte Eigenschaften, und der Rest des Codes funktioniert oft einfach weiter. JavaScript ist jedoch nicht so tolerant wie HTML und CSS — wenn die JavaScript-Engine auf Fehler oder nicht erkannte Syntax stößt, wird sie oft Fehler werfen.
Es gibt einige Strategien zum Umgang mit JavaScript-Fehlern in Ihrem Code; lassen Sie uns die gängigsten erkunden.
Konditionale
TODO
try...catch
TODO
Fehler werfen
TODO
Feature-Detection
Die Feature-Detection ist nützlich, wenn Sie planen, neue JavaScript-Features zu verwenden, die möglicherweise nicht in allen Browsern unterstützt werden. Testen Sie das Feature und führen Sie dann bedingt Code aus, um eine akzeptable Erfahrung sowohl in Browsern zu bieten, die das Feature unterstützen, als auch in denen, die es nicht unterstützen. Als kurzes Beispiel hat die Geolocation-API (die verfügbare Standortdaten für das Gerät, auf dem der Webbrowser läuft, bereitstellt) einen Haupteinstiegspunkt für ihre Nutzung — eine geolocation
-Eigenschaft, die im globalen Navigator-Objekt verfügbar ist. Daher können Sie erkennen, ob der Browser Geolocation unterstützt oder nicht, indem Sie etwas wie das Folgende verwenden:
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
// show the location on a map, perhaps using the Google Maps API
});
} else {
// Give the user a choice of static maps instead
}
Hilfe finden
Es gibt viele andere Probleme, denen Sie mit JavaScript (und HTML und CSS!) begegnen werden, wodurch das Wissen, wie man online Antworten findet, von unschätzbarem Wert ist.
Unter den besten Quellen für Unterstützungsinformationen sind MDN (das ist, wo Sie sich gerade befinden!), stackoverflow.com und caniuse.com.
- Um das Mozilla Developer Network (MDN) zu nutzen, führen die meisten Leute eine Suchmaschinensuche der Technologie durch, zu der sie Informationen suchen, plus den Begriff "mdn", zum Beispiel "mdn HTML video".
- caniuse.com bietet Support-Informationen sowie einige nützliche externe Ressourcenlinks. Zum Beispiel siehe https://caniuse.com/#search=video (Sie müssen nur das Feature, nach dem Sie suchen, in das Textfeld eingeben).
- stackoverflow.com (SO) ist eine Forum-Seite, auf der Sie Fragen stellen und andere Entwickler ihre Lösungen teilen, vorherige Beiträge nachsehen und anderen Entwicklern helfen können. Es wird geraten, zu schauen, ob es bereits eine Antwort auf Ihre Frage gibt, bevor Sie eine neue Frage posten. Zum Beispiel haben wir "Autofokus in HTML-Dialog deaktivieren" bei SO gesucht und schnell Deaktiviere showModal-Autofokussierung mit HTML-Attributen gefunden.
Abgesehen davon versuchen Sie, in Ihrer bevorzugten Suchmaschine nach einer Antwort auf Ihr Problem zu suchen. Es ist oft nützlich, nach spezifischen Fehlermeldungen zu suchen, wenn Sie welche haben — andere Entwickler werden wahrscheinlich dieselben Probleme wie Sie gehabt haben.
Zusammenfassung
Das ist also Debugging und Fehlerbehandlung bei JavaScript. Einfach, oder? Vielleicht nicht so einfach, aber dieser Artikel sollte Ihnen zumindest einen Einstieg geben und einige Ideen, wie Sie die JavaScript-bezogenen Probleme angehen können, auf die Sie stoßen werden.
Das war's für das Modul Dynamisches Scripting mit JavaScript; Gratulation zum Erreichen des Endes! Im nächsten Modul helfen wir Ihnen, JavaScript-Frameworks und -Bibliotheken zu erkunden.