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.
<script
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 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.