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 äußerst komplex, nachdem sie einen bestimmten Zeitraum ausgeführt haben. 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 throw new Error() uns throw . Ausnahmen, die beim Aufrufen der Browser -API auftreten, sind jedoch nicht unbedingt so einfach zu erfassen. 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.
Wenn bekannt ist, dass einige Browser-APIs Ausnahmen werfen, müssen wir den Anruf in try-catch einsetzen, um das gesamte Programm aufgrund von Fehlern in einen illegalen Zustand einzugeben. Zum Beispiel ist window.localStorage eine solche API.
try {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 try-catch gesteckt werden.
listeners.forEach(function(listener) {versuchen {
Hörer();
} catch (error) {
ReporterRor (Fehler);
}
});
Für Orte, an denen try-catch nicht abdecken kann, kann sie nur durch window.onerror eingerichtet werden.
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 window.onerror nur window.onerror . In Anbetracht der Tatsache, dass der Standardentwurf auch window.onerror definiert, müssen wir nur window.onerror verwenden.
Angenommen, wir haben eine reportError -Funktion, um gefangene Ausnahmen zu sammeln und sie dann in Stapel an den serverseitigen Speicher für Abfrage und Analyse zu senden. Welche Informationen möchten wir dann sammeln? Weitere nützliche Informationen sind: Fehlertyp ( name ), Fehlermeldung ( message ), Skriptdateiadresse ( script ), Zeilennummer ( line ), Spaltennummer ( column ) und Stack Trace ( stack ). Wenn eine Ausnahme über try-catch erfasst wird, befinden sich alle diese Informationen auf dem Error (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.
Wenn das Error von uns selbst erstellt wird, wird error.message von uns gesteuert. Grundsätzlich, was wir in error.message message window.onerror (Der Browser wird tatsächlich leicht modifiziert, z. B. das Hinzufügen 'Uncaught Error: ' error.message .) Daher können wir die Attribute serialisieren, über die wir besorgt sind (z. B. JSON.Stringify ) sie im window.onerror Dies ist natürlich auf Error beschränkt, die wir selbst erstellen.
Die Browserhersteller kennen auch die Einschränkungen, denen Menschen bei der Verwendung window.onerror unterliegen, und fügen damit beginnen, window.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. Chrome sagte jedoch, dass es besser wäre, das gesamte Error in den fünften Parameter zu setzen, und Sie können alle Attribute, einschließlich benutzerdefinierter Attribute, lesen. Infolgedessen bewegt sich Chrome schneller, ein neues window.onerror Die Signatur wird in Chrome 30 implementiert, was zum folgenden Schreiben des Standardentwurfs führt.
Regelmäßigkeit der Attributewindow.onerror = function(Errormessage,
scripturi,
Leinenumme,
Spaltennummer,
Fehler
) {
if (Fehler) {
ReporterRor (Fehler);
} anders {
Reporterror ({{
Nachricht: ErrorMessage,
Skript: scripturi,
Linie: Leinenumberne,
Spalte: Spaltennummer
});
}
}
Die Namen der Error script die wir zuvor diskutiert Error , basieren auf filename -Benennungsmethoden. Daher benötigen wir auch eine spezielle Funktion, um das Error 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 Format der stack . Diese Eigenschaft speichert die Stapelinformationen einer Ausnahme, wenn sie in Form von einfachem Text auftritt. . Name ( identifier ), Datei ( script ), Zeilennummer ( line ) und Spaltennummer ( column ).
Wenn Sie auch einen Fehler mit der Meldung 'Script error.' aufgetreten 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 die URI dieser Online-Bank in script.src -Attribut. 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 Quellskriptdateien geworfen werden, und hinterlässt nur eine unveränderte Nachricht wie 'Script error.' und 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 von Chrome und Firefox als nutzlosem 'Script error.' verursacht.
Wenn Sie diese Einschränkung umgehen möchten, stellen Sie einfach sicher, dass die Skriptdatei und die Seite selbst gleich sind. Aber würden die Einlegen von Skriptdateien auf Servern, die nicht von CDN beschleunigt werden, die Download -Geschwindigkeit des Benutzers verringern? Eine Lösung besteht darin, die Skriptdatei weiterhin auf dem CDN zu platzieren, mit XMLHttpRequest den Inhalt wieder durch CORs herunterzuladen und dann ein <script> -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:
<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 sicherstellen. Vergessen Sie nicht, dass Schritt 2 ausgeführt werden kann.
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:
<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 von scheduleRemoteScript und scheduleInlineScript implementieren und sicherstellen, dass sie vor dem ersten <script> -Tag definiert sind, mit dem die externe Skriptdatei verweist, und die verbleibenden <script> -Tags werden in das obige Formular umgeschrieben. Beachten Sie, dass die sofort ausgeführte step2 -Funktion in einer größeren code platziert wurde. Die code 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 scheduleInlineScript 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 ihn selbst implementieren.
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 error.script und dann die eindeutige Zeilennummer über error.line gefunden werden. Da sie alle in der Seite eingebetteten Codes sind, <script> mehrere <script> -Tags nicht durch error.script unterschieden werden. .
Um Zeilennummernkonflikte zu vermeiden, können wir einige Zeilennummern so verschwenden, damit sich die vom tatsächlichen Code in jedem <script> -Tag verwendeten Zeilennummernintervalle nicht miteinander überlappen. Angenommen, der tatsächliche Code in jedem <script> -Tag überschreitet beispielsweise 1000 Zeilen nicht, kann ich den Code in der ersten <script> -TAG für Zeile 11000 aufnehmen lassen und den zweiten <script> den Code im Code markieren lassen Netzt sich Zeile 10012000 (1000 leere Linie vor dem Einfügen eingefügt), der Code des dritten <script> -Tags in Zeile 20013000 (2000 leere Zeile vor dem Einfügen) und so weiter. Anschließend verwenden wir das data-* , um diese Informationen für eine einfache Rückprüfung aufzuzeichnen.
<scriptdata-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 5 Verarbeitung bedeutet dies, error.line ein error.line 3005 beträgt, dass der tatsächliche error.script 'http://cdn.com/step3.js' Wir können diese Zeilennummer -Überprüfung der zuvor erwähnten reportError -Funktion durchführen.
Da wir nicht garantieren können, dass jede Skriptdatei nur 1000 Zeilen enthält, ist es auch möglich, dass einige Skriptdateien von wesentlich weniger als 1000 Zeilen sind, sodass jedes <script> -Tag nicht mehr 1000 Zeilen zuweisen müssen. 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.
Die Sicherheitsbeschränkungen, die Browser für Inhalte aus verschiedenen Quellen auferlegt haben, sind natürlich nicht auf das <script> -Tag 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 <img> -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" verwendet wird, entspricht es anonyme CORs.
Warum kann das <script> <img> 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="use-credentials" , 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 dynamisch zurückzugeben, um CORs basierend auf Anfragen zu authentifizieren.
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 jetzt Google Analytics-Dienste anbieten, die JavaScript-Ausnahmen erfassen, müssen Sie dies selbst tun, wenn Sie die Details und Prinzipien verstehen möchten.