Obsługa wyjątków JavaScript


82

Jaka jest najlepsza technika wychwytywania WSZYSTKICH wyjątków generowanych w JavaScript?

Oczywiście najlepszą techniką jest użycie try ... catch. Ale w przypadku oddzwaniania asynchronicznego i tak dalej może to być trudne.

Wiem, że przeglądarki IE i Gecko obsługują window.onerror, ale co z Operą i Safari?

Oto kilka przypadków testowych, dla których chciałbym mieć centralne rozwiązanie do obsługi wyjątków:

// 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);
}

Jeśli myślisz o innych przypadkach testowych, wspomnij o nich. Kilka z tych przypadków wspomina o metodzie ErrorHandler.handleError. To tylko sugerowana wskazówka podczas korzystania z try ... catch.


Tylko dlatego, że jest jasne, że nie zauważyłeś komentarzy do mojej odpowiedzi: wygląda na to, że zagłosowałeś w dół za „stwierdzone w pytaniu”, kiedy brzmi: „ale co z Operą i Safari?” Odpowiedziałem konkretnie na postawione tutaj pytanie. WTF?
powiek

1
W WebKit window.onerrorzaginięcie jest problemem od 2003 roku , ale wygląda na to, że w końcu został rozwiązany . Oczywiście Opera pozostanie uparta.
josh3736

FYI window.onerror działa dobrze w - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Vitaliy Kaplich

11
Nie wiem, dlaczego to zostało zamknięte. Zagłosowano na ponowne otwarcie.
ripper234

1
Zgoda, to przydatne pytanie. Jedyne, o czym przychodzi mi do głowy, to to, że CasperOne obawiał się, że zamiast tego stanie się to czymś w rodzaju dyskusji o wojnie w przeglądarce?
Jordan Reiter

Odpowiedzi:


23

Jeśli używasz biblioteki takiej jak jQuery do przypisywania wszystkich programów obsługi zdarzeń, możesz użyć kombinacji window.onerrori zawinąć kod modułu obsługi zdarzeń jQuery i gotową funkcję funkcją obsługi błędów (zobacz: Śledzenie błędów JavaScript: Dlaczego window.onerror Is Not Enough ).

  • window.onerror: przechwytuje wszystkie błędy w IE (i większość błędów w Firefoksie), ale nic nie robi w Safari i Opera.
  • Programy obsługi zdarzeń jQuery: przechwytuje błędy zdarzeń jQuery we wszystkich przeglądarkach.
  • Funkcja gotowa do jQuery: wyłapuje błędy inicjalizacji we wszystkich przeglądarkach.

Przeczytałem już artykuł, który nie oferuje żadnego rozwiązania. Nie używam jQuery, ale martwię się tym, co sugerujesz. Chcesz powiedzieć, że jQuery zjada wyjątki ?! A może po prostu zapewniają funkcję logowania (która jest przydatna dopiero po udzieleniu odpowiedzi na moje pierwotne pytanie)?
harley.333

jQuery nie robi nic specjalnego z wyjątkami. Ale jeśli używasz jQuery do dodawania wszystkich swoich zdarzeń, daje to jedno miejsce na dodanie instrukcji try catch i kodu obsługi błędów, jak wyjaśniono w drugim linku w mojej odpowiedzi.
Karl

2
Podany link został przeniesiony: blogs.cozi.com/tech/2008/04/…
natacado

1
Czy to nadal prawda? Właśnie wypróbowałem normalne onerrorpodejście do obsługi w Safari + Chrome i wydaje się, że działa poprawnie.
Juri

Link, który podałeś, dlaczego „to nie wystarczy”, jest dość starą informacją i obecnie nie jest.
vsync,

21

Wydaje się, że WebKit (Safari, Chrome itp.) Obsługuje teraz onerror.

Oryginalny post: O ile wiem, WebKit / Safari nie obsługuje onerrorwydarzenia. Co jest cholernym wstydem.


19
Nie, nie jest. Zapytany w pytaniu: „ale co z Operą i Safari?”
powiek

Tak jak w przypadku, odpowiedziałem konkretnie na pytanie postawione w pytaniu.
powiek

8
Myślę, że miał na myśli "co [mam zrobić] z Operą i Safari [które nie mają window.onerror]?"
nickf

10
Może @nickf, ale jeśli tak, to jest bardzo źle sformułowany, a moja interpretacja jest w najgorszym razie zrozumiała, aw najlepszym razie najbardziej prawdopodobna. Jest to dość słaba powodem ludzi do głosowania moją odpowiedź w dół, zwłaszcza biorąc pod uwagę, że kwestia nie podać go, a inni czytelnicy mogą korzystać z wyciągu pozytywny lub negatywny.
powiek

Wydaje się, że teraz Chrome go obsługuje.
Daniel X Moore

7

Właściwie podejście jquery nie jest takie złe. Widzieć:

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

i:

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

11
dla każdego, kto znajdzie to teraz - jquery faktycznie zaleca, aby nie wiązać zdarzenia ze zdarzeniem window.error - zobacz link do dokumentacji powyżej. Wyodrębnij: moduł obsługi zdarzeń błędu jQuery nie powinien być dołączony do obiektu okna. [...] Zamiast tego użyj window.onerror.
zcrar70

ofc to nie powinno być związane w ten sposób, to nielogiczne! wiele błędów może się wydarzyć do czasu złożenia tej oferty (jeśli w ogóle się udało ...)
vsync

6

Złap wszystkie wyjątki za pomocą własnej obsługi wyjątków i użyj 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 zgłosi błąd natywny, ponieważ nie ma bloku try-catch.

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


4

try-catchnie zawsze jest najlepszym rozwiązaniem. Na przykład w Chrome 7.0 tracisz ładny ślad stosu w oknie konsoli. Ponowne zgłoszenie wyjątku nie pomaga. Nie znam żadnego rozwiązania, które zachowuje ślady stosu i pozwala reagować na wyjątek.


2

Przy odrobinie pracy możliwe jest uzyskanie śladów stosu, które są w miarę kompletne we wszystkich przeglądarkach.

Nowoczesne Chrome i Opera (czyli wszystko oparte na silniku renderującym Blink) w pełni obsługują wersję roboczą specyfikacji HTML 5 dla ErrorEvent i window.onerror . W obu tych przeglądarkach możesz window.onerrorpoprawnie użyć lub (zadziwiająco!) Powiązać ze zdarzeniem „błąd”:

// 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);
})

Niestety Firefox, Safari i IE są nadal dostępne i musimy je również wspierać. Ponieważ śledzenie stosu nie jest dostępne w programie, window.onerrormusimy wykonać trochę więcej pracy.

Okazuje się, że jedyną rzeczą, jaką możemy zrobić, aby uzyskać ślady stosu z błędów, jest zawinięcie całego kodu w plik try{ }catch(e){ } blok, a następnie sprawdzenie pliku e.stack. Możemy nieco uprościć ten proces za pomocą funkcji zwanej wrap, która pobiera funkcję i zwraca nową funkcję z dobrą obsługą błędów.

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;
};

To działa. Każda funkcja, którą zawiniesz ręcznie, będzie miała dobrą obsługę błędów.

Możesz wysyłać dane za pomocą znacznika obrazu w następujący sposób

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;
}

Jednak musisz zrobić zaplecze, aby zebrać dane i front-end, aby zwizualizować dane.

W Atatus pracujemy nad rozwiązaniem tego problemu. Atatus to nie tylko śledzenie błędów, ale także monitorowanie rzeczywistych użytkowników.

Spróbuj https://www.atatus.com/

Zastrzeżenie: jestem programistą internetowym w Atatus.


1

Prawdą jest, że w nowoczesnych przeglądarkach podpięcie window.onerror pod kątem błędów, które pojawiają się na samej górze, wraz z dodaniem modułów obsługi zdarzeń jQuery dla błędów Ajax, wyłapuje praktycznie wszystkie obiekty Error wrzucane do kodu klienta. Jeśli ręcznie konfigurujesz program obsługi dla window.onerror, w nowoczesnych przeglądarkach odbywa się to window.addEventListener('error', callback), podczas gdy w IE8 / 9 musisz wywołać window.attachEvent('onerror', callback).

Zauważ, że powinieneś następnie rozważyć środowisko, w którym te błędy są obsługiwane, i powód tego. Wyłapywanie jak największej liczby błędów za pomocą ich śledzenia stosu to jedno, ale pojawienie się nowoczesnych narzędzi programistycznych F12 rozwiązuje ten przypadek użycia podczas lokalnego wdrażania i debugowania. Punkty przerwania itp. Dają więcej danych niż są dostępne w programach obsługi, szczególnie w przypadku błędów zgłaszanych przez biblioteki innych firm, które zostały załadowane z żądań CORS. Musisz podjąć dodatkowe kroki, aby poinstruować przeglądarkę, aby udostępniła te dane.

Kluczowym problemem jest dostarczenie tych danych w środowisku produkcyjnym, ponieważ Twoi użytkownicy mają gwarancję, że będą uruchamiać znacznie szerszą gamę przeglądarek i wersji, niż możesz przetestować, a Twoja witryna / aplikacja będzie się łamać w nieoczekiwany sposób, niezależnie od tego, ile kontroli jakości rzucisz to.

Aby sobie z tym poradzić, potrzebujesz narzędzia do śledzenia błędów produkcyjnych, które wychwytuje każdy błąd zgłaszany w przeglądarkach użytkownika, gdy używają Twojego kodu, i wysyła je do punktu końcowego, gdzie dane mogą być przeglądane przez Ciebie i używane do naprawiania błędów w miarę ich występowania . W Raygun (zrzeczenie się: pracuję w Raygun) włożyliśmy sporo wysiłku, aby zapewnić doskonałe wrażenia, ponieważ istnieje wiele pułapek i problemów, które należy wziąć pod uwagę, których naiwna implementacja zostanie pominięta.

Na przykład jest szansa, że ​​będziesz łączyć i minimalizować swoje zasoby JS, co oznacza, że ​​błędy wyrzucane ze zminimalizowanego kodu będą zawierały niepotrzebne ślady stosu z zniekształconymi nazwami zmiennych. W tym celu potrzebujesz narzędzia do kompilacji do generowania map źródłowych (zalecamy UglifyJS2 dla tej części potoku), a moduł śledzenia błędów do akceptowania i przetwarzania tych map, zmieniając zniekształcone ścieżki stosu z powrotem w czytelne dla człowieka. Raygun robi to wszystko po wyjęciu z pudełka i zawiera punkt końcowy interfejsu API do akceptowania map źródłowych w miarę ich generowania przez proces kompilacji. Jest to kluczowe, ponieważ muszą być niepubliczne, w przeciwnym razie każdy mógłby unieszkodliwić Twój kod, negując jego cel.

Raygun4js biblioteki klienta jest również wyposażony window.onerrorzarówno dla nowoczesnych i starszych przeglądarek, jak również jQuery haki out-of-the-box, tak aby ustawić to trzeba tylko dodać:

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

Istnieje również wiele wbudowanych funkcji, w tym możliwość mutowania ładunku błędu przed jego wysłaniem, dodawanie tagów i niestandardowych danych, metadanych użytkownika, który widział błąd. Eliminuje to również ból związany z uzyskiwaniem dobrych śladów stosu z wyżej wymienionych skryptów CORS innych firm, co rozwiązuje przerażający „błąd skryptu” (który nie zawiera komunikatu o błędzie ani śladu stosu).

Bardziej istotnym problemem jest to, że ze względu na ogromną liczbę odbiorców w sieci witryna wygeneruje wiele tysięcy zduplikowanych wystąpień każdego błędu. Usługa śledzenia błędów, taka jak Raygun, ma sprytne rozwiązania, które pozwalają łączyć je w grupy błędów, dzięki czemu nie utoniesz w zalewie powiadomień i możesz zobaczyć każdy faktyczny błąd gotowy do naprawienia.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.