Das Material, dessen Übersetzung wir heute veröffentlichen, ist der Behandlung von JS-Fehlern mit
window.onerror
. Dies ist ein spezielles Browserereignis, das ausgelöst wird, wenn nicht erfasste Fehler auftreten. Hier
onerror
, wie Sie Fehler mit dem
onerror
Ereignishandler abfangen und Informationen dazu an den Server des Website-Entwicklers senden. Dieser Handler kann als Grundlage für Ihr eigenes System zum Sammeln und Analysieren von Fehlerinformationen verwendet werden. Darüber hinaus ist es einer der wichtigsten Mechanismen, die in
fehlerorientierten Bibliotheken wie
Raven-js verwendet werden .

Auf das window.onerror-Ereignis warten
Sie können auf das Ereignis
onerror
window.onerror
indem Sie
window.onerror
Funktion
window.onerror
, die die Rolle eines Fehlerbehandlers spielt:
window.onerror = function(msg, url, lineNo, columnNo, error) { // ... ... return false; }
Diese Funktion wird aufgerufen, wenn ein Fehler auftritt. Die folgenden Argumente werden an sie übergeben:
msg
- Fehlermeldung. Zum Beispiel ist Uncaught ReferenceError: foo is not defined
.url
- die Adresse des Skripts oder Dokuments, in dem der Fehler aufgetreten ist. Zum Beispiel /dist/app.js
.lineNo
- Zeilennummer, in der der Fehler aufgetreten ist (falls unterstützt).columnNo
- die Spaltennummer der Zeile (falls unterstützt).error
- das error
(falls unterstützt).
Die ersten vier Argumente teilen dem Entwickler mit, in welchem Skript, in welcher Zeile und in welcher Spalte dieser Zeile ein Fehler aufgetreten ist. Das letzte Argument, ein Objekt vom Typ
Error
, ist vielleicht das wichtigste aller Argumente. Reden wir darüber.
Fehlerobjekt und Error.prototype.stack-Eigenschaft
Auf den ersten Blick ist das
Error
nichts Besonderes. Es enthält drei ganz normale Eigenschaften -
message
,
fileName
und
lineNumber
. Diese Daten können angesichts der an den Ereignishandler
window.onerror
übergebenen Informationen als redundant betrachtet werden.
Der tatsächliche Wert ist in diesem Fall die nicht standardmäßige Eigenschaft
Error.prototype.stack
. Diese Eigenschaft ermöglicht den Zugriff auf den Aufrufstapel (Fehlerstapel) und ermöglicht es Ihnen, herauszufinden, was zum Zeitpunkt des Fehlers im Programm passiert ist. Welcher Funktionsaufruf ging seinem Auftreten voraus. Die Ablaufverfolgung von Aufrufstapeln kann ein kritischer Bestandteil des Debugging-Prozesses sein. Und obwohl die
stack
Eigenschaft nicht Standard ist, ist sie in allen modernen Browsern verfügbar.
So sieht die
stack
Eigenschaft des Fehlerobjekts in Chrome 46 aus.
"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript.\_evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript.\_evaluateAndWrap (<anonymous>:808:34)"
Vor uns liegt eine unformatierte Zeichenfolge. Wenn der Inhalt dieser Eigenschaft in dieser Form dargestellt wird, ist es unpraktisch, damit zu arbeiten. So sieht das gleiche nach der Formatierung aus.
Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
Nach der Formatierung sieht der Fehlerstapel jetzt viel klarer aus. Es wird sofort klar, warum die
stack
beim Debuggen von Fehlern sehr wichtig ist.
Hier läuft jedoch nicht alles reibungslos. Die
stack
Eigenschaft ist nicht standardisiert, sondern wird in verschiedenen Browsern unterschiedlich implementiert. Hier sehen Sie beispielsweise, wie der Fehlerstapel in Internet Explorer 11 aussieht.
Error: foobar at bar (Unknown script code:2:5) at foo (Unknown script code:6:5) at Anonymous function (Unknown script code:11:5) at Anonymous function (Unknown script code:10:2) at Anonymous function (Unknown script code:1:73)
Sie können im Vergleich zum vorherigen Beispiel sehen, dass hier nicht nur ein anderes Format zur Darstellung von Stapelrahmen verwendet wird, sondern auch, dass für jeden Rahmen weniger Daten vorhanden sind. Chrome identifiziert beispielsweise Instanzen der Verwendung des
new
Schlüsselworts und bietet detailliertere Informationen zu anderen Ereignissen (insbesondere zu Funktionsaufrufen.
_evaluateOn
und.
_evaluateAndWrap
). Gleichzeitig haben wir hier nur verglichen, was IE und Chrome herausgeben. Andere Browser verwenden ihre eigenen Ansätze, um Daten über den Stapel anzuzeigen und die in diesen Daten enthaltenen Informationen auszuwählen.
Um all dies zu einem einheitlichen Erscheinungsbild zu bringen, können Sie Tools von Drittanbietern verwenden. Beispielsweise verwendet raven-js hierfür TraceKit. Stacktrace.js und einige andere Projekte dienen demselben Zweck.
Funktionen der window.onerror-Unterstützung durch verschiedene Browser
Das Ereignis
windows.onerror
existiert seit einiger Zeit in Browsern. Insbesondere ist es in IE6 und Firefox 2 zu finden. Das Problem hierbei ist, dass alle Browser
windows.onerror
auf unterschiedliche Weise implementieren. Dies betrifft beispielsweise die Anzahl und Struktur der Argumente, die an die Handler dieses Ereignisses übergeben werden.
In der folgenden Tabelle sind
onerror
Argumente aufgeführt, die in den wichtigsten Browsern an den
onerror
Handler übergeben wurden.
Browser
| Nachricht
| URL
| lineNo
| colNo
| errorObj
|
Firefox
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Es gibt
|
Chrome
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Es gibt
|
Rand
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Es gibt
|
IE 11
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Es gibt
|
IE10
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Nein
|
IE 9.8
| Es gibt
| Es gibt
| Es gibt
| Nein
| Nein
|
Safari 10 und höher
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Es gibt
|
Safari 9
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Nein
|
Android Browser 4.4
| Es gibt
| Es gibt
| Es gibt
| Es gibt
| Nein
|
Es ist wahrscheinlich nicht überraschend, dass Internet Explorer 8, 9 und 10
onerror
nur eingeschränkt unterstützen. Es mag jedoch ungewöhnlich erscheinen, dass die Unterstützung für das Fehlerobjekt im Safari-Browser nur in der 10. Version erschien, die 2016 veröffentlicht wurde. Darüber hinaus gibt es ältere mobile Geräte, die den Standard-Android-Browser verwenden, der das Fehlerobjekt ebenfalls nicht unterstützt. In modernen Android-Versionen wurde dieser Browser durch Chrome Mobile ersetzt.
Wenn uns kein Fehlerobjekt zur Verfügung steht, liegen keine Daten zur Stapelverfolgung vor. Dies bedeutet, dass Browser, die das Objekt des Fehlers nicht unterstützen, im Standardskript keine
onerror
für die Verwendung des
onerror
Handlers bereitstellen. Und das ist, wie gesagt, sehr wichtig.
Polyfill-Entwicklung für window.onerror mit dem try / catch-Konstrukt
Um Informationen über den Stapel in Browsern abzurufen, die die Übergabe eines
onerror
an den
onerror
Handler nicht unterstützen, können Sie den folgenden Trick verwenden. Sie können den Code in ein
try/catch
Konstrukt einschließen und die Fehler selbst abfangen. Das resultierende Fehlerobjekt enthält in allen modernen Browsern die
stack
Eigenschaft.
Schauen Sie sich den
invoke()
, der die angegebene Methode des Objekts aufruft und ihm ein Array von Argumenten übergibt.
function invoke(obj, method, args) { return obj[method].apply(this,args); }
Hier erfahren Sie, wie Sie es verwenden.
invoke(Math, 'max', [1,2])
Hier ist das gleiche
invoke()
, aber jetzt ist der Methodenaufruf in
try/catch
, wodurch Sie mögliche Fehler abfangen können.
function invoke(obj, method, args) { try { return obj[method].apply(this,args); } catch(e) { captureError(e);// throw e;// } } invoke(Math,'highest',[1,2]); // , Math.highest
Natürlich ist es sehr teuer, solche Strukturen manuell an allen Stellen hinzuzufügen, an denen sie möglicherweise benötigt werden. Diese Aufgabe kann durch die Erstellung einer universellen Hilfsfunktion vereinfacht werden.
function wrapErrors(fn) { // if(!fn.__wrapped__) { fn.__wrapped__ = function() { try{ return fn.apply(this,arguments); }catch(e){ captureError(e);// throw e;// } }; } return fn.__wrapped__; } var invoke = wrapErrors(function(obj, method, args) { returnobj[method].apply(this,args); }); invoke(Math,'highest',[1,2]);//, Math.highest
Da JavaScript ein Single-Threaded-Code-Ausführungsmodell verwendet, sollte dieser Wrapper nur mit den Funktionsaufrufen verwendet werden, die am Anfang neuer Stapel stehen. Es ist nicht erforderlich, alle Funktionsaufrufe darin zu verpacken.
Infolgedessen stellt sich heraus, dass diese Funktion an folgenden Stellen verwendet werden muss:
- Wo die Anwendung startet (z. B. bei Verwendung von jQuery in der Funktion
$(document).ready
) - In Ereignishandlern (z. B. in
addEventListener
oder in Konstruktionen der Form $.fn.click
) - In Rückrufen, die von Timer-Ereignissen aufgerufen werden (z. B.
setTimeout
oder requestAnimationFrame
).
Hier ist ein Beispiel mit der Funktion
wrapErrors
.
$(wrapErrors(function () {// doSynchronousStuff1();// setTimeout(wrapErrors(function () { doSynchronousStuff2();// })); $('.foo').click(wrapErrors(function () { doSynchronousStuff3();// })); }));
Solche Konstruktionen können dem Code selbst hinzugefügt werden, dies ist jedoch eine zu zeitaufwändige Aufgabe. Als praktische Alternative in solchen Situationen können Sie Bibliotheken für die Arbeit mit Fehlern in Betracht ziehen, die beispielsweise über Mechanismen verfügen,
addEventListener
und
setTimeout
Tools zum
addEventListener
Fehlern
addEventListener
.
Fehlerübertragung auf den Server
Jetzt haben wir also die Möglichkeit, Fehlerinformationen entweder mit
windows.onerror
oder mithilfe von Hilfsfunktionen basierend auf
try/catch
abzufangen. Diese Fehler treten auf der Client-Seite auf, und nach ihrem Abfangen möchten wir sie beheben und Maßnahmen ergreifen, um sie zu beseitigen. Dazu müssen sie auf unseren Server übertragen werden. Dazu müssen Sie einen Webdienst vorbereiten, der Informationen über Fehler über HTTP empfängt und diese dann zur weiteren Verarbeitung speichert, z. B. in eine Protokolldatei oder Datenbank schreiben.
Befindet sich dieser Webdienst in derselben Domäne wie die Webanwendung, reicht
XMLHttpRequest
aus. Das folgende Beispiel zeigt, wie Sie mit einer Funktion AJAX-Abfragen von jQuery ausführen, um Daten auf einen Server zu übertragen.
function captureError(ex){ var errorData = { name:ex.name,// : ReferenceError message:ex.line,// : x is undefined url:document.location.href, stack:ex.stack// ; , ! }; $.post('/logger/js/',{ data:errorData }); }
Beachten Sie, dass Sie sich um die Unterstützung solcher Anforderungen kümmern müssen, wenn Sie domänenübergreifende Anforderungen senden müssen, um Informationen zu Fehlern an den Server zu senden.
Zusammenfassung
Sie haben die Grundlagen zum Erstellen eines Dienstes zum Abfangen von Fehlern und zum Senden von Informationen über diese an den Server gelernt. Insbesondere haben wir hier folgende Themen untersucht:
- Funktionen des
onerror
Ereignisses und dessen Unterstützung in verschiedenen Browsern. - Verwenden des
try/catch
Mechanismus zum Abrufen von Informationen zum Aufrufstapel in Fällen, in denen onerror
die Arbeit mit dem onerror
nicht unterstützt. - Übertragen Sie Fehlerdaten auf den Server des Entwicklers.
Nachdem Sie die Funktionsweise der oben genannten Mechanismen kennengelernt haben, haben Sie Grundkenntnisse erworben, mit denen Sie Ihr eigenes System für die Arbeit mit Fehlern erstellen und zusätzliche Details während der Arbeit klären können. Möglicherweise ist dieses Szenario besonders relevant für Fälle, in denen es sich um eine bestimmte Anwendung handelt, in der beispielsweise aus Sicherheitsgründen die Verwendung von Bibliotheken von Drittanbietern nicht geplant ist. Wenn Ihre Anwendung die Verwendung von Code von Drittanbietern zulässt, finden Sie sehr gut das richtige Tool zur Überwachung von JS-Fehlern. Zu diesen Tools gehören
Sentry ,
Rollbar ,
TrackJS und andere ähnliche Projekte.
Liebe Leser! Welche Tools zur Überwachung von JS-Fehlern verwenden Sie?
