Freundlicher Hinweis: Dieser Artikel enthält viele GIF-Demo-Animationen. Bitte lesen Sie auf Mobilgeräten möglichst in einer WLAN-Umgebung.
Vorwort: Debugging-Fähigkeiten sind eine unverzichtbare Fähigkeit in jeder technologischen Forschung und Entwicklung. Die Beherrschung verschiedener Debugging-Techniken erzielt mit halbem Aufwand doppelten Erfolg. Zum Beispiel Probleme schnell lokalisieren, die Ausfallwahrscheinlichkeit verringern, bei der Analyse logischer Fehler helfen und so weiter. Heutzutage, da die Front-End-Entwicklung im Internet immer wichtiger wird, ist es besonders wichtig, Front-End-Entwicklungs-Debugging-Fähigkeiten zu beherrschen, um Entwicklungskosten zu senken und die Arbeitseffizienz in der Front-End-Entwicklung zu verbessern.
Dieser Artikel erklärt verschiedene Front-End-JS-Debugging-Techniken eine nach der anderen. Vielleicht sind Sie bereits versiert, dann wiederholen wir sie gemeinsam. Vielleicht gibt es Methoden, die Sie noch nicht gesehen haben, dann lernen Sie sie doch gemeinsam. Vielleicht wissen Sie noch nicht, wie man debuggt, dann nutzen Sie diese Gelegenheit, um die Wissenslücke zu schließen.
1. Debugging-Meister auf Veteranen-Niveau: Alert
Das war eine Ära, in der das Internet gerade erst begann. Front-End-Webseiten wurden hauptsächlich zur Inhaltsanzeige verwendet, und Browserskripte konnten nur sehr einfache Hilfsfunktionen für Seiten bereitstellen. Damals liefen Webseiten hauptsächlich in Browsern, die von IE6 dominiert wurden, und die JS-Debugging-Fähigkeiten waren sehr schwach. Debugging konnte nur über die im Window-Objekt integrierte alert-Methode erfolgen. Damals sah es wahrscheinlich so aus:

Es sollte beachtet werden, dass der hier zu sehende Effekt nicht der ist, der damals in IE-Browsern zu sehen war, sondern der Effekt in einer höheren IE-Version. Außerdem schien es damals keine so fortschrittliche Konsole zu geben, und alert wurde im echten JS-Code der Seite verwendet. Obwohl die alert-Debugging-Methode primitiv ist, hatte sie damals wirklich unauslöschlichen Wert, und selbst heute hat sie noch ihren Platz.
2. Der Debugging-König der neuen Generation: Console
Da JS im Web-Frontend immer mehr leisten kann, werden seine Aufgaben größer und seine Bedeutung nimmt stetig zu. Die traditionelle alert-Debugging-Methode kann den verschiedenen Frontend-Entwicklungsszenarien allmählich nicht mehr gerecht werden. Außerdem erscheinen die von alert eingeblendeten Debugging-Informationen in einem recht unattraktiven Fenster und verdecken einen Teil des Seiteninhalts, was sie etwas unfreundlich macht.
Andererseits erfordern alert-Debugging-Meldungen, dass Anweisungen wie "alert(xxxxx)" in die Programmlogik eingefügt werden, um normal zu funktionieren, und alert blockiert außerdem das weitere Rendern der Seite. Das bedeutet, dass Entwickler diese Debug-Codes nach dem Debugging manuell entfernen müssen, was ziemlich lästig ist.
Daher haben eine neue Generation von Browsern, darunter Firefox, Chrome und IE, nach und nach JS-Debugging-Konsolen eingeführt, die Formen wie "console.log(xxxx)" unterstützen, um Debugging-Informationen auf der Konsole auszugeben, ohne die Seitendarstellung direkt zu beeinflussen. Am Beispiel von IE sieht das so aus:

Nun, verabschieden wir uns von dem hässlichen alert-Popup. Und die aufstrebenden Stars, angeführt vom Chrome-Browser, erweiterten die Console um reichere Funktionen:

Glaubst du, das ist schon befriedigend genug? Die Fantasie des Chrome-Entwicklungsteams ist wirklich bewundernswert:

Okay, ich bin ein wenig abgeschweift. Kurz gesagt, das Aufkommen der Konsole und des in den Browser integrierten Console-Objekts hat das Debugging in der Frontend-Entwicklung enorm erleichtert.
Manche fragen vielleicht: Muss diese Art von Debug-Code nach dem Debugging nicht auch entfernt werden?
Zu diesem Problem: Wenn du zuerst eine Existenzprüfung durchführst, bevor du das console-Objekt verwendest, dann wird die Geschäftslogik nicht beschädigt, wenn du es nicht löschst. Natürlich solltest du um der Code-Sauberkeit willen diese Debug-Codes, die nichts mit der Geschäftslogik zu tun haben, nach dem Debugging trotzdem möglichst löschen.
3. JS-Breakpoint-Debugging
Breakpoint: eine der Funktionen des Debuggers; er kann das Programm bei Bedarf unterbrechen, was die Analyse erleichtert. Du kannst Breakpoints auch in einer Debugging-Sitzung setzen, und beim nächsten Mal lässt du das Programm einfach automatisch bis zur gesetzten Breakpoint-Position laufen, wo es am zuvor gesetzten Breakpoint anhält. Das erleichtert die Bedienung erheblich und spart Zeit. — Baidu Baike
JS-Breakpoint-Debugging bedeutet, in den Browser-Entwicklertools Breakpoints zum JS-Code hinzuzufügen, sodass die JS-Ausführung an einer bestimmten Position stoppt, was es Entwicklern erleichtert, das Code-Segment zu analysieren und die Logik zu behandeln. Um die Wirkung des Breakpoint-Debuggings zu beobachten, haben wir vorab ein Stück JS-Code vorbereitet:

Der Code ist sehr einfach: Definiere eine Funktion, übergib zwei Zahlen, addiere zu jeder eine zufällige Ganzzahl und gib dann die Summe der beiden Zahlen zurück. Nehmen wir die Chrome-Entwicklertools als Beispiel und schauen wir uns die grundlegende Methode des JS-Breakpoint-Debuggings an.
3.1. Sources-Breakpoint
Zuerst können wir an der Konsolenausgabe in der obigen Abbildung sehen, dass der Testcode eigentlich normal hätte laufen sollen. Aber warum "eigentlich"? Weil in der Funktion eine Zufallszahl hinzugefügt wird. Ist das endgültige Ergebnis wirklich korrekt? Das ist eine sinnlose Vermutung, aber angenommen, ich möchte nun verifizieren: die beiden in die Funktion übergebenen Zahlen, die hinzugefügten Zufallszahlen und die endgültige Summe. Wie machen wir das also?
Methode 1, die zuvor erwähnte gewöhnlichste: Ob mit alert oder console, wir können es so verifizieren:

Aus der obigen Abbildung geht hervor, dass wir drei Zeilen Konsolencode hinzugefügt haben, um die Datenvariablen auszugeben, die uns interessieren. Schließlich können wir anhand der Ausgabe in der Konsole (Console-Panel) klar verifizieren, ob der gesamte Berechnungsprozess normal ist, und damit die Verifikationsanforderungen unserer Problemstellung erfüllen.
Methode 2: Der offensichtliche Nachteil von Methode 1 besteht darin, dass sie viel redundanten Code hinzufügt. Als Nächstes sehen wir, ob die Verwendung von Breakpoints zur Verifizierung bequemer ist. Schauen wir uns zunächst an, wie man einen Breakpoint hinzufügt und welche Wirkung das Anhalten an ihm hat:

Wie in der Abbildung gezeigt, ist der Prozess des Hinzufügens eines Breakpoints zu einem Codeabschnitt: "F12 (Ctrl + Shift + I), um die Entwicklertools zu öffnen" → "auf das Menü Sources klicken" → "die entsprechende Datei im linken Baum finden" → "auf die Zeilennummernspalte klicken", um das Hinzufügen/Entfernen eines Breakpoints in der aktuellen Zeile abzuschließen. Sobald der Breakpoint hinzugefügt wurde, die Seite aktualisieren, und die JS-Ausführung stoppt am Breakpoint. In der Sources-Oberfläche sehen Sie alle Variablen und Werte im aktuellen Gültigkeitsbereich. Verifizieren Sie einfach jeden Wert, um die Verifizierungsanforderungen unserer Problemstellung zu erfüllen.
Nun ergibt sich das Problem: Aufmerksame Leser werden bemerken, dass die angezeigten Werte der Variablen a und b bereits addiert wurden, wenn die Ausführung des Codes den Breakpoint erreicht, und wir die anfänglichen 10 und 20, die beim Aufruf der Funktion sum übergeben wurden, nicht sehen können. Was tun wir also? Wir müssen zurückgehen und zunächst einige Grundlagen des Breakpoint-Debuggings lernen. Nach dem Öffnen des Sources-Panels sehen wir tatsächlich den folgenden Inhalt. Folgen wir dem Mauszeiger und schauen wir, was jeder Teil bedeutet:

Von links nach rechts sind die Funktionen, die durch jedes Symbol dargestellt werden:
- Pause/Resume script execution: Skriptausführung anhalten/fortsetzen (das Programm hält an, wenn es den nächsten Breakpoint erreicht).
- Step over next function call: den Funktionsaufruf im nächsten Schritt ausführen (zur nächsten Zeile springen).
- Step into next function call: in die aktuelle Funktion springen.
- Step out of current function: aus der aktuell ausgeführten Funktion herausspringen.
- Deactivate/Activate all breakpoints: alle Breakpoints deaktivieren/aktivieren (ohne sie zu entfernen).
- Pause on exceptions: automatisch einen Breakpoint bei Ausnahmen setzen.
An diesem Punkt wurden die Funktionstasten des Breakpoint-Debuggings größtenteils vorgestellt. Als Nächstes können wir unseren Programmcode Zeile für Zeile durchgehen und uns ansehen, wie sich jede Variable nach der Ausführung jeder Zeile ändert, wie in der folgenden Abbildung gezeigt:

Wie oben können wir den gesamten Prozess der Variablen a und b von ihren Anfangswerten über das zwischendurch erfolgende Hinzufügen zufälliger Werte bis hin zur schließlichen Berechnung der Summe und Ausgabe des Endergebnisses sehen. Die Verifizierungsanforderungen der Problemstellung zu erfüllen, ist mehr als einfach.
Für die verbleibenden Funktionstasten ändern wir unseren Testcode geringfügig und verwenden ein GIF-Bild, um ihre Verwendung zu demonstrieren:

Eines ist hier zu beachten: Die Funktion, Variablenwerte direkt im Codebereich anzuzeigen, ist eine neue Funktion, die in neueren Versionen von Chrome hinzugefügt wurde. Wenn Sie noch eine ältere Version von Chrome verwenden, können Sie Variableninformationen an einem Breakpoint möglicherweise nicht direkt anzeigen. In diesem Fall können Sie den Mauszeiger über den Variablennamen bewegen und kurz innehalten, um den Variablenwert zu sehen. Sie können den Variablennamen auch mit der Maus auswählen, mit der rechten Maustaste klicken und "Add to watch" wählen, um ihn im Watch-Panel anzuzeigen. Diese Methode funktioniert auch für Ausdrücke. Darüber hinaus können Sie an einem Breakpoint zum Console-Panel wechseln, den Variablennamen direkt in der Konsole eingeben und Enter drücken, um Variableninformationen anzuzeigen. Dieser Teil ist relativ einfach. In Anbetracht der Länge des Artikels werde ich keine Abbildungsdemonstrationen bereitstellen.
3.2. Debugger-Breakpoint
Der sogenannte Debugger-Breakpoint ist eigentlich ein Name, den ich selbst vergeben habe; ich kenne den Fachbegriff nicht. Konkret bedeutet es, dass man eine "debugger;"-Anweisung zum Code hinzufügt. Wenn die Codeausführung diese Anweisung erreicht, wird automatisch eine Unterbrechung ausgelöst. Die nachfolgenden Vorgänge sind fast genau dieselben wie das Hinzufügen eines Breakpoints im Sources-Panel, mit dem einzigen Unterschied, dass Sie die Anweisung nach dem Debuggen löschen müssen.
Da sich diese Methode, abgesehen von der unterschiedlichen Art, den Breakpoint zu setzen, in Funktion und Wirkung nicht vom Hinzufügen eines Breakpoints im Sources-Panel unterscheidet, warum gibt es sie dann noch? Ich denke, der Grund ist folgender: Während der Entwicklung stoßen wir gelegentlich auf Situationen, in denen HTML-Fragmente (einschließlich eingebettetem JS-Code) asynchron geladen werden, und dieser Teil des JS-Codes kann im Sources-Baum nicht gefunden werden, sodass wir in den Entwicklertools nicht direkt Breakpoints hinzufügen können. Wenn wir einen Breakpoint zu asynchron geladenen Skripten hinzufügen möchten, kommt "debugger;" ins Spiel. Schauen wir uns seine Wirkung direkt anhand eines GIF-Bildes an:

4. DOM-Breakpoint-Debugging
DOM-Breakpoints setzen, wie der Name schon sagt, Breakpoints auf DOM-Elemente, um Debugging-Zwecke zu erreichen. In der tatsächlichen Verwendung landet die Wirkung der Breakpoints letztlich innerhalb der JS-Logik. Schauen wir uns nacheinander die konkrete Wirkung jeder Art von DOM-Breakpoint an.
4.1. Unterbrechen, wenn sich untergeordnete Knoten innerhalb eines Knotens ändern (Unterbrechen bei Änderungen am Unterbaum)
Da die Frontend-Entwicklung zunehmend komplexer wird, wächst der Frontend-JS-Code und die Logik wird immer komplexer. Eine scheinbar einfache Webseite geht meist mit großen Mengen an JS-Code einher, der viele Operationen zum Hinzufügen, Löschen und Ändern von DOM-Knoten umfasst. Unweigerlich gibt es Situationen, in denen es schwierig ist, ein Stück Code direkt über den JS-Code zu lokalisieren, aber wir können den relevanten DOM-Knoten schnell über das Elements-Panel der Entwicklertools lokalisieren. An diesem Punkt wird das Auffinden von Skripten über DOM-Breakpoints besonders wichtig. Schauen wir es uns anhand der GIF-Demonstration an:

Die obige Abbildung demonstriert die Wirkung von Breakpoints, die durch Hinzufügen, Löschen und Vertauschen der Reihenfolge von untergeordneten Knoten (li) des ul ausgelöst werden. Beachten Sie, dass das Ändern der Attribute oder Inhalte von untergeordneten Knoten keine Breakpoints auslöst.
4.2. Unterbrechen, wenn sich Knotenattribute ändern (Unterbrechen bei Attributänderungen)
Andererseits, da die vom Frontend verarbeitete Geschäftslogik zunehmend komplexer wird, wächst die Abhängigkeit vom Speichern bestimmter Daten. Das Speichern temporärer Daten in (benutzerdefinierten) Attributen von DOM-Knoten ist in vielen Fällen die bevorzugte Wahl für Entwickler. Insbesondere nachdem der HTML5-Standard die Unterstützung für benutzerdefinierte Attribute verbessert hat (z. B. dataset, data-* usw.), ist die Verwendung von Attributzuweisungen immer weiter verbreitet. Daher bietet Chrome Developer Tools auch Unterstützung für Breakpoints bei Attributänderungen, und der Effekt sieht ungefähr wie folgt aus:

Bei dieser Methode ist ebenfalls Vorsicht geboten: Jede Operation an den Attributen von untergeordneten Knoten löst keinen Breakpoint am Knoten selbst aus.
4.3. Unterbrechen, wenn der Knoten entfernt wird (Break on node removal)
Dieser DOM-Breakpoint ist sehr einfach zu setzen, und die Auslösebedingung ist klar: wenn der Knoten gelöscht wird. Daher wird diese Methode normalerweise beim Ausführen der Anweisung `parentNode.removeChild(childNode)` verwendet. Diese Methode wird nicht oft verwendet.
Die oben vorgestellten Debugging-Methoden sind im Grunde diejenigen, die wir in der täglichen Entwicklung häufig verwenden. Richtig eingesetzt, können sie fast alle Probleme in unserer täglichen Entwicklung bewältigen. Die Entwicklertools berücksichtigen jedoch auch weitere Szenarien und bieten zusätzliche Breakpoint-Methoden, wie in der Abbildung gezeigt:

5、XHR Breakpoints
In den letzten Jahren hat die Frontend-Entwicklung dramatische Veränderungen durchgemacht – von anfangs wenig bekannt bis heute äußerst beliebt. Ajax treibt umfangreiche Webanwendungen an, und mobile WebApp-Single-Page-Anwendungen boomen. All dies ist untrennbar mit dem XMLHttpRequest-Objekt verbunden, und "XHR Breakpoints" ist eine Breakpoint-Debugging-Funktion, die speziell für asynchrone Vorgänge entwickelt wurde.

Wir können Breakpoint-Bedingungen für asynchrone Breakpoints über die Schaltfläche "+" auf der rechten Seite von "XHR Breakpoints" hinzufügen. Wenn die URL einer asynchronen Anfrage diese Bedingung erfüllt, löst die JS-Logik automatisch einen Breakpoint aus. Die Demo-Animation zeigt die Breakpoint-Position nicht, weil die Demo die gekapselte ajax-Methode von jQuery verwendet und der Code minifiziert wurde, sodass kein offensichtlicher Effekt zu sehen ist. Tatsächlich wird der XHR-Breakpoint bei der Anweisung `xhr.send()` ausgelöst.
Die Stärke von XHR-Breakpoints liegt in der Möglichkeit, Breakpoint-Regeln anzupassen, was bedeutet, dass wir Breakpoints für eine Gruppe, eine einzelne oder sogar alle asynchronen Anfragen setzen können – sehr leistungsstark. Allerdings scheint diese Funktion in der täglichen Entwicklung nicht viel genutzt zu werden, zumindest nutze ich sie nicht oft. Dafür gibt es wahrscheinlich zwei Gründe: Erstens tritt dieser Bedarf an Breakpoint-Debugging im täglichen Geschäft selten auf; zweitens basiert die Frontend-Entwicklung in dieser Phase größtenteils auf JS-Frameworks. Selbst das einfachste jQuery kapselt Ajax bereits gut, und nur sehr wenige Menschen kapseln Ajax-Methoden selbst. Um die Codegröße zu reduzieren, wählen Projekte außerdem meist minifizierte Codebibliotheken, wodurch die Verfolgung von XHR-Breakpoints relativ erschwert wird.
6、Event-Listener-Breakpoints
Event-Listener-Breakpoints, d. h. das Setzen von Breakpoints anhand von Ereignisnamen. Wenn ein Ereignis ausgelöst wird, hält der Breakpoint an der Stelle an, an der das Ereignis gebunden ist. Event-Listener-Breakpoints listen alle Seiten- und Skript-Ereignisse auf, einschließlich Maus, Tastatur, Animation, Timer, XHR usw. Dies verringert die Schwierigkeit beim Debuggen von ereignisbezogener Geschäftslogik erheblich.

Das Demo-Beispiel zeigt die Breakpoint-Effekte, wenn das click-Ereignis ausgelöst wird und wenn setTimeout gesetzt wird. Das Beispiel zeigt, dass nach Auswahl des click-Ereignis-Breakpoints das Klicken beider Schaltflächen Breakpoints ausgelöst hat und beim Setzen von setTimeout der Breakpoint "Set Timer" ausgelöst wird.
Debugging ist ein sehr wichtiger Teil der Projektentwicklung. Es hilft uns nicht nur, Probleme schnell zu lokalisieren, sondern spart auch unsere Entwicklungszeit. Die Beherrschung verschiedener Debugging-Methoden wird Ihrer Karriereentwicklung sicherlich viele Vorteile bringen. Bei so vielen Debugging-Methoden erfordert die Auswahl einer für Ihr aktuelles Anwendungsszenario jedoch Erfahrung und kontinuierliches Ausprobieren und Ansammeln.
Autor: Zheng Wujiang
Quelle: http://seejs.me/2016/03/27/jsdebugger/