Front-End-Ingenieure wissen alle, dass JavaScript grundlegende Funktionen für Ausnahmebereitschaften hat. Wir können einen neuen Fehler () werfen, und der Browser macht auch eine Ausnahme, wenn wir den API -Fehler aufrufen. Es wird jedoch geschätzt, dass die meisten Front-End-Ingenieure nie darüber nachgedacht haben, diese Ausnahmeinformationen zu sammeln
Solange sich die Aktualisierung nach einem JavaScript -Fehler nicht vermehrt, kann der Benutzer das Problem durch Auffrischen lösen, und der Browser stürzt nicht ab, und es wird in Ordnung sein, wenn es nicht passiert ist. Diese Annahme war der Fall, bevor die einseitige App populär wurde. Die aktuelle Single -Page -App ist nach einem bestimmten Zeitraum extrem komplex. Benutzer haben möglicherweise mehrere Eingabevorgänge durchgeführt, bevor sie hierher kamen. Wie können sie erfrischen, wenn sie sagen, dass sie wollen? Würden Sie die vorherigen Operationen nicht vollständig überarbeiten? Daher müssen wir diese Ausnahmeinformationen erfassen und analysieren, und dann können wir den Code ändern, um zu vermeiden, dass die Benutzererfahrung beeinflusst wird.
Wie man Ausnahmen fängt
Wir haben geschrieben, einen neuen Fehler () zu werfen. Wenn wir erfassen wollen, können wir es sicherlich erfassen, weil wir sehr gut wissen, wo Wurf geschrieben ist. Ausnahmen, die beim Aufrufen der Browser -API auftreten, sind jedoch nicht unbedingt so einfach zu fangen. Einige APIs sagen, dass Ausnahmen in den Standard geworfen werden, und einige APIs haben nur individuelle Browser aufgrund von Implementierungsunterschieden oder -fehlern Ausnahmen. Für das erstere können wir es auch durch Try-Catch fangen, für das letztere müssen wir auf globale Ausnahmen hören und es dann fangen.
Versuche
Wenn bekannt ist, dass einige Browser-APIs Ausnahmen werfen, müssen wir den Anruf in den Versuch einsetzen, um das gesamte Programm aufgrund von Fehlern in einen illegalen Zustand einzugeben. Zum Beispiel ist Window.LocalStorage eine solche API. Eine Ausnahme wird ausgelöst, nachdem das Schreiben von Daten die Kapazitätsgrenze überschreitet, und dies gilt auch im privaten Browsing -Modus von Safari.
Die Codekopie lautet wie folgt:
versuchen {
LocalStorage.SetItem ('Datum', Datum.Now ());
} catch (error) {
ReporterRor (Fehler);
}
Ein weiteres gängiges Try-Catch-Szenario sind Rückrufe. Da der Code der Rückruffunktion unkontrollierbar ist, wissen wir nicht, wie gut der Code ist und ob andere APIs, die Ausnahmen werfen, aufgerufen werden. Damit keine anderen Codes nach dem Aufrufen des Rückrufs aufgrund von Rückruffehlern ausgeführt werden können, muss der Anruf wieder in den Versuchs-Catch gesteckt werden.
Die Codekopie lautet wie folgt:
Hörer.foreach (Funktion (Hörer) {
versuchen {
Hörer();
} catch (error) {
ReporterRor (Fehler);
}
});
window.onError
Für Orte, die Try-Catch nicht abdecken können, kann sie nur über das Fenster.
Die Codekopie lautet wie folgt:
window.onError =
Funktion (ErrorMessage, Scripturi, Leinenumber) {
Reporterror ({{
Nachricht: ErrorMessage,
Skript: scripturi,
Zeile: Leinenumberne
});
}
Achten Sie darauf, nicht klug zu sein und verwenden Sie Window.AdDeventListener oder Window.attachevent, um Window.onError anzuhören. Viele Browser implementieren nur Fenster. In Anbetracht der Tatsache, dass der Standardentwurf auch Window.OnError definiert, müssen wir nur Windows.onError verwenden.
Eigentum fehlen
Angenommen, wir haben eine Reporterror-Funktion, um gefangene Ausnahmen zu sammeln und sie dann in Stapel an serverseitige Speicher für Abfrage und Analyse zu senden. Welche Informationen möchten wir sammeln? Weitere nützliche Informationen sind: Fehlertyp (Name), Fehlermeldung (Nachricht), Skriptdateiadresse (Skript), Zeilennummer (Zeile), Spaltennummer (Spalte) und Stapelverfolgung. Wenn eine Ausnahme über Try-Catch erfasst wird, befinden sich alle diese Informationen auf dem Fehlerobjekt (unterstützt von Mainstream-Browsern), sodass Reporterror diese Informationen auch sammeln kann. Wenn es jedoch über window.onError erfasst wird, wissen wir alle, dass diese Ereignisfunktion nur 3 Parameter enthält, sodass die unerwarteten Informationen dieser 3 Parameter verloren gehen.
Serialisieren Sie Nachrichten
Wenn das Fehlerobjekt von uns selbst erstellt wird, wird die Message von uns gesteuert. Grundsätzlich, was wir in Fehler einfügen. (Der Browser wird tatsächlich leicht Änderungen vornehmen, z. B. das Hinzufügen des "Uncornd -Fehlers": Präfix.) Daher können wir die Attribute serialisieren, über die wir besorgt sind (wie z. Dies ist natürlich auf das Fehlerobjekt beschränkt, das wir selbst erstellt haben.
Der fünfte Parameter
Die Browserhersteller kennen auch die Einschränkungen, denen Menschen bei der Verwendung von window.onError unterliegen, und fügen damit beginnen, Windows.onError neue Parameter hinzuzufügen. In Anbetracht der Tatsache, dass nur Zeilennummern und keine Spaltennummern sehr symmetrisch zu sein scheinen, haben er zuerst die Spaltenzahlen hinzugefügt und sie im vierten Parameter platziert. Was jedoch jeder mehr besorgt ist, ist, ob sie den gesamten Stapel bekommen können, so dass Firefox sagte, es wäre besser, den Stapel in den fünften Parameter zu setzen. Aber Chrome sagte, dass es besser wäre, das gesamte Fehlerobjekt in den fünften Parameter zu setzen. Jedes Attribut, das Sie lesen möchten, einschließlich benutzerdefinierter Attribute. Da Chrome schneller ist, wurde in Chrome 30 ein neues Fenster in der Eerror -Signatur implementiert, was zum folgenden Schreiben des Standardentwurfs führte.
Die Codekopie lautet wie folgt:
Fenster.onError = Funktion (
Errormessage,
scripturi,
Leinenumme,
Spaltennummer,
Fehler
) {
if (Fehler) {
ReporterRor (Fehler);
} anders {
Reporterror ({{
Nachricht: ErrorMessage,
Skript: scripturi,
Linie: Leinenumberne,
Spalte: Spaltennummer
});
}
}
Regelmäßigkeit der Attribute
Die Namen der zuvor diskutierten Fehlerobjekteigenschaften basieren auf Chrom -Benennungsmethoden. Verschiedene Browser nennen jedoch die Fehlerobjekteigenschaften unterschiedlich. Beispielsweise wird die Skriptdateiadresse in Chrome, aber in Firefox, als Skript bezeichnet. Daher benötigen wir auch eine spezielle Funktion, um das Fehlerobjekt zu normalisieren, dh verschiedene Attributnamen einem einheitlichen Attributnamen zuzuordnen. Für bestimmte Praktiken finden Sie in diesem Artikel. Obwohl die Browser -Implementierung aktualisiert wird, ist es für niemanden zu schwierig, eine solche Zuordnungstabelle beizubehalten.
Ähnlich ist das Stack Trace -Format. Diese Eigenschaft spart die Stapelinformationen einer Ausnahme, wenn sie im Klartext auftritt. Da die von jedem Browser verwendeten Textformate unterschiedlich sind, müssen auch einen regulären Ausdruck beibehalten, um den Funktionsnamen (Kennung), Datei (Skript), Zeilennummer (Zeile) und Spaltennummer (Spalte) jedes Rahmens aus einfachem Text zu extrahieren.
Sicherheitsbeschränkungen
Wenn Sie auch auf einen Fehler mit der Meldung "Skript -Fehler" gestoßen sind, werden Sie verstehen, wovon ich spreche, was tatsächlich die Einschränkungen des Browsers für Skriptdateien aus verschiedenen Quellen ist. Der Grund für diese Sicherheitsbeschränkung ist wie folgt: Angenommen, die von einem Online-Bankier zurückgegebene HTML nach der Anmeldung unterscheidet sich von der HTML, die von einem anonymen Benutzer gesehen wird. Eine Website von Drittanbietern kann den URI dieser Online-Bank in das script.src-Attribut einfügen. Natürlich kann HTML nicht als JS analysiert werden, daher stellt der Browser eine Ausnahme aus, und diese Website von Drittanbietern kann feststellen, ob der Benutzer angemeldet ist, indem der Standort der Ausnahme analysiert wird. Aus diesem Grund filtert der Browser alle Ausnahmen, die von verschiedenen Quell -Skriptdateien geworfen werden, und hinterlässt nur eine unveränderte Nachricht wie "Skriptfehler". Alle anderen Attribute verschwinden.
Für Websites einer bestimmten Skala ist es normal, dass Skriptdateien auf CDNs platziert werden und verschiedene Quellen platziert werden. Selbst wenn Sie selbst eine kleine Website erstellen, können gemeinsame Frameworks wie JQuery und Backbone die Version der öffentlichen CDN direkt verweisen, um Benutzer -Downloads zu beschleunigen. Diese Sicherheitsbeschränkung verursacht also einige Probleme, was die Ausnahmeinformationen verursacht, die wir von Chrome und Firefox sammeln, als nutzloser "Skriptfehler".
CORS
Wenn Sie diese Einschränkung umgehen möchten, stellen Sie einfach sicher, dass die Skriptdatei und die Seite selbst den gleichen Ursprung haben. Aber würden Sie keine Skriptdateien auf Servern platzieren, die von CDN nicht beschleunigt werden, um die Download -Geschwindigkeit des Benutzers zu verlangsamen? Eine Lösung besteht darin, die Skriptdatei weiterhin auf dem CDN zu platzieren, mit XMLHTTPREQUET den Inhalt wieder durch CORs herunterzuladen und dann ein <skript> -Tag zu erstellen, um sie in die Seite zu injizieren. Der in der Seite eingebettete Code ist natürlich der gleiche Ursprung.
Dies ist einfach zu sagen, aber es gibt viele Details zu implementieren. Ein einfaches Beispiel geben:
Die Codekopie lautet wie folgt:
<script src = "http://cdn.com/step1.js"> </script>
<Script>
(Funktion Step2 () {}) ();
</script>
<script src = "http://cdn.com/step3.js"> </script>
Wir alle wissen, dass, wenn es in Schritt1, Schritt 2 und Schritt 3 Abhängigkeiten gibt, es ausschließlich in dieser Reihenfolge ausgeführt werden muss, sonst kann ein Fehler auftreten. Der Browser kann parallel Schritt 1- und Schritt3 -Dateien anfordern, die Bestellung ist jedoch bei der Ausführung garantiert. Wenn wir den Dateiinhalt von Schritt1 und Schritt 3 mit XMLHTTPREquest erhalten, müssen wir die richtige Reihenfolge selbst sicherstellen. Vergessen Sie außerdem nicht Schritt2. STEP2 kann ausgeführt werden, wenn Schritt1 in nicht blockierender Form heruntergeladen wird. Daher müssen wir auch Schritt 2 beeinträchtigen und darauf warten, dass Schritt 1 vor der Ausführung abgeschlossen wird.
Wenn wir bereits über einen vollständigen Satz von Tools verfügen, um <script> Tags für verschiedene Seiten auf der Website zu generieren, müssen wir diesen Satz von Tools anpassen, um Änderungen an <Script> -Tags vorzunehmen:
Die Codekopie lautet wie folgt:
<Script>
Scheduleremotescript ('http://cdn.com/step1.js');
</script>
<Script>
planInLineScript (Funktionscode () {
(Funktion Step2 () {}) ();
});
</script>
<Script>
Scheduleremotescript ('http://cdn.com/step3.js');
</script>
Wir müssen die beiden Funktionen Scheduleremotescript und planInLineScript implementieren und sicherstellen, dass sie vor dem ersten <skript> -Tag definiert sind, mit dem die externe Skriptdatei verweist, und dann werden die verbleibenden <Script> -Tags in das obige Formular umgeschrieben. Beachten Sie, dass die sofort ausgeführte Step2 -Funktion in einer größeren Codefunktion platziert wurde. Die Codefunktion wird nicht ausgeführt, sondern nur ein Container, so dass der ursprüngliche Schritt2 -Code ohne Flucht beibehalten wird, aber nicht sofort ausgeführt wird.
Als nächstes müssen wir einen vollständigen Mechanismus implementieren, um sicherzustellen, dass der von Scheduleremotescript basierende Dateiinhalt basierend auf der Adresse und dem von planInLinescript direkt erhaltenen Code einzeln in der richtigen Reihenfolge ausgeführt werden kann. Ich werde den detaillierten Code hier nicht geben. Wenn Sie interessiert sind, können Sie es selbst implementieren.
Zeilennummerprüfung
Wenn Sie Inhalte über CORS und das Einfügen von Code in die Seite erhalten, können Sie Sicherheitsbeschränkungen durchbrechen. Es wird jedoch ein neues Problem einführen, dh Konflikte für die Zeilennummer. Ursprünglich könnte die eindeutige Skriptdatei über Fehler.Script und dann die eindeutige Zeilennummer über Fehler.Line gefunden werden. Da alle auf der Seite eingebetteten Codes alle Codes sind, können mehrere <Script> -Tags nicht durch Fehler.Script unterschieden werden. Die Zeilennummer in jedem <skript> -Tag wird jedoch aus 1 berechnet, wodurch wir keine Ausnahmeinformationen verwenden können, um den Quellcodespeicherort zu finden, an dem sich der Fehler befindet.
Um Zeilennummernkonflikte zu vermeiden, können wir einige Zeilennummern so verschwenden, damit sich die vom tatsächlichen Code in jedem <skript> -Tag verwendeten Zeilennummernintervalle nicht miteinander überlappen. Unter der Annahme, dass der tatsächliche Code in jedem <Script> -Tag überschreitet, überschreitet ich beispielsweise 1000 Zeilen nicht, dann kann ich den Code in der ersten <skript> -Tag -Occupy -Zeile 11000 zulassen, der Code im zweiten <Script> -Tag occupy line 10012000 (1000 leere Zeilen wurde vorgefügt) der Code im dritten <Script> Tag 20013000 (2000 leere Zeilen zuvor) und so oben. Anschließend verwenden wir das Datenattribut, um diese Informationen für eine einfache Rückprüfung aufzuzeichnen.
Die Codekopie lautet wie folgt:
<Skript
data-src = "http://cdn.com/step1.js"
Data-Line-Start = "1"
>
// Code für Schritt 1
</script>
<skript data-line-start = "1001">
// '/n' * 1000
// Code für Schritt 2
</script>
<Skript
data-src = "http://cdn.com/step3.js"
Data-Line-Start = "2001"
>
// '/n' * 2000
// Code für Schritt 3
</script>
Nach dieser Verarbeitung bedeutet dies, wenn ein Fehlerfehler 3005 beträgt, dass der tatsächliche Fehler.
Da wir nicht garantieren können, dass jede Skriptdatei nur 1000 Zeilen enthält, ist es auch möglich, dass einige Skriptdateien wesentlich weniger als 1000 Zeilen sind. Daher müssen jedem <Script> -Tag nicht ein 1000 Zeilenintervall zugewiesen. Wir können Intervalle basierend auf der tatsächlichen Anzahl von Skriptlinien zuweisen und nur sicherstellen, dass die von jedem <Script> -Tag verwendeten Intervalle nicht überlappen.
Crossorigin -Attribut
Die Sicherheitsbeschränkungen, die Browser für Inhalte aus verschiedenen Quellen auferlegt haben, sind natürlich nicht auf <Script> -Tags beschränkt. Da XMLHTTPREquest diese Einschränkung durch CORs durchbrechen kann, warum werden Ressourcen direkt über Tags verwiesen, die nicht zulässig sind? Das ist sicherlich in Ordnung.
Die Einschränkung der Verweise auf verschiedene Quell -Skriptdateien für <Script> -Tags gilt auch für die Verweise auf verschiedene Quellbilddateien für <MeMG> -Tags. Wenn ein <img> -Tag eine andere Quelle ist, die einmal in der Zeichnung <Canvas> verwendet wird, wird die <Canvas> zu einem geschriebenen Zustand, sodass die Website nicht autorisierte Bilddaten aus verschiedenen Quellen über JavaScript stehlen kann. Später löste das <img> Tag dieses Problem durch Einführung des Crossorigin -Attributs. Wenn Crossorigin = "Anonymous" ist, entspricht es anonymen CORs; Wenn Crossorigin = "Anwendungszüchter" ist, entspricht dies einem zertifizierten CORS.
Warum kann das <Script> -Tag dies nicht <img> tag dies können? Daher fügte der Browserhersteller das gleiche Crossorigin -Attribut zum <Script> -Tag hinzu, um die oben genannten Sicherheitsbeschränkungen zu lösen. Jetzt ist die Unterstützung von Chrome und Firefox für diese Eigenschaft völlig kostenlos. Safari behandelt Crossorigin = "Anonymous" als Crossorigin = "Anwendungszüchter", und das Ergebnis ist, dass Safari die Authentifizierung als Fehler behandelt, wenn der Server nur anonyme CORs unterstützt. Da der CDN -Server aus Leistungsgründen nur statische Inhalte zurückgibt, ist es unmöglich, den HTTP -Header, der zur Authentifizierung von CORs erforderlich ist, dynamisch zurückzugeben. Safari entspricht nicht in der Lage, diese Funktion zu verwenden, um das obige Problem zu lösen.
Zusammenfassen
Die Handhabung der JavaScript -Ausnahme sieht einfach aus und unterscheidet sich nicht von anderen Sprachen, aber es ist nicht so einfach, alle Ausnahmen zu fangen und die Eigenschaften zu analysieren. Obwohl einige Dienste von Drittanbietern Google Analytics-ähnliche Dienste anbieten, die JavaScript-Ausnahmen erfassen, müssen Sie dies selbst tun, wenn Sie die Details und Prinzipien verstehen möchten.