Behandlung von JavaScript-Ausnahmen


82

Was ist die beste Technik, um ALLE in JavaScript ausgelösten Ausnahmen abzufangen?

Offensichtlich ist die beste Technik, try ... catch zu verwenden. Aber mit ansynchronen Rückrufen usw. kann das schwierig werden.

Ich weiß, dass IE- und Gecko-Browser window.onerror unterstützen, aber was ist mit Opera und Safari?

Hier sind einige Testfälle, für die ich eine zentrale Lösung für die Ausnahmebehandlung haben möchte:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
    myMessage: "stuff",
    customProperty: 5,
    anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
    var test2 = null;
    test2.arg = 5;
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
    throw (new Error("Goodbye"));
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
    throw "Goodbye again";
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
    throw {
        myMessage: "stuff",
        customProperty: 5,
        anArray: [1, 2, 3]
    };
} catch(e) {
    ErrorHandler.handleError(e);
}

Wenn Sie an andere Testfälle denken, erwähnen Sie diese bitte. In einigen dieser Fälle wird eine ErrorHandler.handleError-Methode erwähnt. Dies ist nur eine empfohlene Richtlinie bei der Verwendung von try ... catch.


Nur weil klar ist, dass Sie die Kommentare zu meiner Antwort nicht bemerkt haben: Sie haben mich anscheinend für "in der Frage angegeben" herabgestimmt, wenn es als Frage lautet: "Aber was ist mit Opera und Safari?" Ich habe speziell eine hier gestellte Frage beantwortet. WTF?
Augenlidlosigkeit

1
In WebKit, window.onerrorhat fehlt da ein Problem 2003 , aber es sieht aus wie es ist endlich gelöst zu werden . Natürlich wird Opera hartnäckig bleiben.
Josh3736

FYI window.onerror funktioniert gut in - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Vitaliy Kaplich

11
Ich bin mir nicht sicher, warum dies geschlossen wurde. Für die Wiedereröffnung gestimmt.
Ripper234

1
Einverstanden, das ist eine nützliche Frage. Ich kann mir nur vorstellen, dass casperOne befürchtet, dass dies stattdessen zu einer Art Browser-Kriegsdiskussion wird.
Jordan Reiter

Antworten:


23

Wenn Sie eine Bibliothek wie jQuery zum Zuweisen aller Ihrer Ereignishandler verwenden, können Sie eine Kombination aus window.onerrordem jQuery-Ereignishandlercode und der Bereitschaftsfunktion mit einer Fehlerbehandlungsfunktion verwenden und diese umschließen (siehe: JavaScript-Fehlerverfolgung: Warum window.onerror nicht ausreicht) ).

  • window.onerror: fängt alle Fehler im IE ab (und die meisten Fehler in Firefox), tut aber nichts in Safari und Opera.
  • jQuery-Ereignishandler: Fängt jQuery-Ereignisfehler in allen Browsern ab.
  • jQuery-Ready-Funktion: Fängt Initialisierungsfehler in allen Browsern ab.

Ich hatte bereits den Artikel gelesen, der keine Lösung bietet. Ich benutze jQuery nicht, aber ich mache mir Sorgen darüber, was Sie damit meinen. Wollen Sie damit sagen, dass jQuery Ausnahmen isst?! Oder bieten sie lediglich eine Protokollierungsfunktion (die erst nützlich ist, nachdem meine ursprüngliche Frage beantwortet wurde)?
Harley.333

jQuery macht mit Ausnahmen nichts Besonderes. Wenn Sie jedoch jQuery zum Hinzufügen aller Ihrer Ereignisse verwenden, können Sie an einer einzigen Stelle Ihre try catch-Anweisung und Ihren Fehlerbehandlungscode hinzufügen, wie im zweiten Link in meiner Antwort erläutert.
Karl

2
Der bereitgestellte Link wurde verschoben: blogs.cozi.com/tech/2008/04/…
natacado

1
Ist das noch wahr? Ich habe gerade den normalen onerrorHandhabungsansatz für Safari + Chrome ausprobiert und scheint ordnungsgemäß zu funktionieren.
Juri

Der Link, den Sie angegeben haben, warum "es nicht genug ist", ist eine ziemlich alte Information und ist jetzt nicht der Fall.
vsync

21

WebKit (Safari, Chrome usw.) scheint nun zu unterstützen onerror.

Ursprünglicher Beitrag: Soweit ich weiß, unterstützt WebKit / Safari die onerrorVeranstaltung nicht. Welches ist eine verdammte Schande.


19
Äh, nein, ist es nicht. In der Frage gestellt: "Aber was ist mit Opera und Safari?"
Augenlidlosigkeit

Wie in habe ich speziell eine Frage beantwortet, die im Fragenbeitrag gestellt wurde.
Augenlidlosigkeit

8
Ich denke, er meinte "was mache ich mit Opera und Safari [die kein window.onerror haben]?"
Nickf

10
@nickf vielleicht, aber wenn ja, ist es sehr schlecht formuliert und meine Interpretation ist im schlimmsten Fall verständlich und im besten Fall am wahrscheinlichsten. Es ist ein ziemlich schlecht Grund für die Menschen meine Antwort nach unten stimmen, zumal die Frage nicht nicht sagen , sie und andere Leser profitieren von einer positiven oder negativer Aussage.
Augenlidlosigkeit

Chrome scheint es jetzt zu unterstützen.
Daniel X Moore

7

Eigentlich ist der jquery-Ansatz nicht so schlecht. Sehen:

http://docs.jquery.com/Events/error#fn

und:

$(window).error(function(msg, url, line){
  $.post("js_error_log.php", { msg: msg, url: url, line: line });
});

11
Für alle, die dies jetzt finden - jquery empfiehlt tatsächlich, ein Ereignis nicht an das window.error-Ereignis zu binden - siehe den obigen Dokumentationslink. Extrahieren: Ein jQuery-Fehlerereignishandler sollte nicht an das Fensterobjekt angehängt werden. [...] Verwenden Sie stattdessen window.onerror.
zcrar70

ofc es soll nicht so gebunden werden, es ist unlogisch! Viele Fehler könnten auftreten, wenn dieses Biding gemacht wurde (wenn es überhaupt erfolgreich gemacht wurde ...)
vsync

6

Fangen Sie alle Ausnahmen mit Ihrem eigenen Ausnahmebehandler ab und verwenden Sie instanceof.

$("inuput").live({
    click : function (event) {
        try {
            if (somethingGoesWrong) {
                throw new MyException();
            }
        } catch (Exception) {
            new MyExceptionHandler(Exception);
        }

    }
});

function MyExceptionHandler(Exception) {
    if (Exception instanceof TypeError || 
        Exception instanceof ReferenceError || 
        Exception instanceof RangeError ||  
        Exception instanceof SyntaxError ||     
        Exception instanceof URIError ) {
        throw Exception; // native error
     } else {
         // handle exception
     }
}

MyExcetpionHandler gibt einen nativen Fehler aus, da kein Try-Catch-Block vorhanden ist.

Besuchen Sie http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/


4

try-catchist nicht immer die beste Lösung. In Chrome 7.0 verlieren Sie beispielsweise die schöne Stapelverfolgung im Konsolenfenster. Das erneute Auslösen der Ausnahme hilft nicht. Ich kenne keine Lösung, die Stapelspuren bewahrt und Sie auf Ausnahmen reagieren lässt.


2

Mit ein wenig Arbeit ist es möglich, Stacktraces zu erhalten, die in allen Browsern einigermaßen vollständig sind.

Modernes Chrome und Opera (dh alles, was auf der Blink-Rendering-Engine basiert) unterstützen die HTML 5-Entwurfsspezifikation für ErrorEvent und vollständig window.onerror. In diesen beiden Browsern können Sie entweder window.onerrordas 'Fehler'-Ereignis verwenden oder (erstaunlicherweise!) Richtig binden:

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendData(data);
})

Leider gibt es Firefox, Safari und IE immer noch und wir müssen sie auch unterstützen. Da der Stacktrace in nicht verfügbar ist, müssen window.onerrorwir etwas mehr arbeiten.

Es stellt sich heraus, dass das einzige, was wir tun können, um Stacktraces von Fehlern zu erhalten, darin besteht, unseren gesamten Code in einen try{ }catch(e){ }Block zu packen und dann e.stack zu betrachten. Wir können den Prozess mit einer Funktion namens wrap etwas vereinfachen, die eine Funktion übernimmt und eine neue Funktion mit guter Fehlerbehandlung zurückgibt.

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendData(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

Das funktioniert. Jede Funktion, die Sie manuell umbrechen, weist eine gute Fehlerbehandlung auf.

Sie können Daten mit dem Image-Tag wie folgt senden

function sendData(data) {
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

Sie müssen jedoch ein Backend durchführen, um die Daten zu sammeln, und ein Frontend, um die Daten zu visualisieren.

Beim Atatus arbeiten wir an der Lösung dieses Problems. Atatus ist mehr als nur eine Fehlerverfolgung. Es bietet eine echte Benutzerüberwachung.

Versuche es https://www.atatus.com/

Haftungsausschluss: Ich bin Webentwickler bei Atatus.


1

Es ist richtig, dass mit modernen Browsern praktisch alle in Ihrem Client-Code ausgelösten Fehlerobjekte abgefangen werden, wenn Sie window.onerror für Fehler einbinden, die ganz nach oben sprudeln, und jQuery-Ereignishandler für Ajax-Fehler hinzufügen. Wenn Sie einen Handler für window.onerror manuell einrichten, geschieht dies in modernen Browsern window.addEventListener('error', callback), während Sie in IE8 / 9 aufrufen müssen window.attachEvent('onerror', callback).

Beachten Sie, dass Sie dann die Umgebung, in der diese Fehler behandelt werden, und den Grund dafür berücksichtigen sollten. Es ist eine Sache, so viele Fehler wie möglich mit ihren Stacktraces abzufangen, aber das Aufkommen moderner F12-Entwicklungstools löst diesen Anwendungsfall beim lokalen Implementieren und Debuggen. Haltepunkte usw. geben Ihnen mehr Daten als von den Handlern verfügbar sind, insbesondere für Fehler, die von Bibliotheken von Drittanbietern ausgelöst wurden, die aus CORS-Anforderungen geladen wurden. Sie müssen zusätzliche Schritte ausführen, um den Browser anzuweisen, diese Daten bereitzustellen.

Das Hauptproblem besteht darin, diese Daten in der Produktion bereitzustellen, da Ihre Benutzer garantiert eine weitaus größere Auswahl an Browsern und Versionen ausführen, als Sie möglicherweise testen können, und Ihre Website / App auf unerwartete Weise beschädigt wird, unabhängig davon, wie viel Qualitätssicherung Sie durchführen es.

Um dies zu handhaben, benötigen Sie einen Produktionsfehler-Tracker, der jeden in den Browsern Ihres Benutzers ausgelösten Fehler aufnimmt, wenn dieser Ihren Code verwendet, und ihn an einen Endpunkt sendet, an dem die Daten von Ihnen angezeigt und zur Behebung der auftretenden Fehler verwendet werden können . Bei Raygun (Haftungsausschluss: Ich arbeite bei Raygun) haben wir uns sehr bemüht, eine großartige Erfahrung dafür zu bieten, da es viele Fallstricke und Probleme gibt, die zu berücksichtigen sind, dass eine naive Implementierung fehlen wird.

Beispielsweise besteht die Möglichkeit, dass Sie Ihre JS-Assets bündeln und minimieren. Dies bedeutet, dass Fehler, die durch minimierten Code ausgelöst werden, Junk-Stacktraces mit beschädigten Variablennamen enthalten. Dazu benötigen Sie Ihr Build-Tool, um Quellkarten zu generieren (wir empfehlen UglifyJS2 für diesen Teil der Pipeline), und Ihren Fehler-Tracker, um diese zu akzeptieren und zu verarbeiten und die verstümmelten Stacktraces wieder in lesbare zu verwandeln. Raygun erledigt dies alles sofort und enthält einen API-Endpunkt, um Quellzuordnungen zu akzeptieren, die von Ihrem Erstellungsprozess generiert werden. Dies ist wichtig, da sie nicht öffentlich zugänglich gemacht werden müssen, da sonst jeder Ihren Code aufheben und seinen Zweck negieren kann.

Die raygun4js Client - Bibliothek kommt auch mit window.onerrorfür modernen und Legacy - Browser sowie jQuery hakt out-of-the-Box, so dass diese einzurichten Sie nur hinzufügen müssen:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

Es gibt auch eine Reihe integrierter Funktionen, einschließlich der Möglichkeit, die Fehlernutzdaten vor dem Senden zu mutieren, Tags und benutzerdefinierte Daten hinzuzufügen, Metadaten für den Benutzer, der den Fehler gesehen hat. Es macht es auch einfacher, gute Stapelspuren aus den oben genannten CORS-Skripten von Drittanbietern zu erhalten, wodurch der gefürchtete 'Skriptfehler' (der keine Fehlermeldung und keine Stapelspur enthält) behoben wird.

Ein wichtigeres Problem ist, dass Ihre Website aufgrund des großen Publikums im Web viele tausend doppelte Instanzen jedes Fehlers generiert. Ein Fehlerverfolgungsdienst wie Raygun verfügt über intelligente Funktionen, um diese in Fehlergruppen zusammenzufassen, damit Sie nicht in einer Flut von Benachrichtigungen ertrinken und jeden tatsächlichen Fehler zur Behebung anzeigen können.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.