Обработка исключений JavaScript


82

Каков наилучший способ перехвата ВСЕХ исключений, возникающих в JavaScript?

Очевидно, что лучший способ - это попробовать ... поймать. Но с асинхронными обратными вызовами и т. Д. Это может быть сложно.

Я знаю, что браузеры IE и Gecko поддерживают window.onerror, но как насчет Opera и Safari?

Вот несколько тестовых примеров, для которых я хотел бы иметь центральное решение для обработки исключений:

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

Если вы думаете о каких-либо других тестовых примерах, укажите их. В некоторых из этих случаев упоминается метод ErrorHandler.handleError. Это всего лишь рекомендуемый совет при использовании try ... catch.


Просто потому, что ясно, что вы не заметили комментариев к моему ответу: кажется, вы проголосовали против меня за «изложенное в вопросе», когда оно читается как вопрос: «а как насчет Opera и Safari?» Я специально ответил на поставленный здесь вопрос. Какого черта?
век

1
В WebKit window.onerrorотсутствие ошибок было проблемой с 2003 года , но похоже, что она наконец решается . Конечно, Opera останется упрямой.
josh3736

FYI window.onerror отлично работает в - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Виталий Каплич

11
Не уверен, почему это было закрыто. Проголосовал за возобновление работы.
ripper234 06

1
Согласен, это полезный вопрос. Единственное, о чем я могу думать, - это то, что casperOne боялся, что вместо этого это станет своего рода дискуссией о войне браузеров?
Джордан Рейтер

Ответы:


23

Если вы используете библиотеку, такую ​​как jQuery, для назначения всех ваших обработчиков событий, вы можете использовать комбинацию window.onerrorи упаковку кода обработчика событий jQuery и готовую функцию с функцией обработки ошибок (см .: Отслеживание ошибок JavaScript: почему window.onerror недостаточно ).

  • window.onerror: ловит все ошибки в IE (и большинство ошибок в Firefox), но ничего не делает в Safari и Opera.
  • Обработчики событий jQuery: обнаруживают ошибки событий jQuery во всех браузерах.
  • Функция готовности jQuery: обнаруживает ошибки инициализации во всех браузерах.

Я уже читал статью, которая не предлагает никакого решения. Я не использую jQuery, но меня беспокоит, о чем вы говорите. Вы хотите сказать, что jQuery ест исключения ?! Или они просто предоставляют функцию ведения журнала (что полезно только после ответа на мой исходный вопрос)?
harley.333

jQuery не делает ничего особенного с Исключениями. Но если вы используете jQuery для добавления всех своих событий, это дает вам единое место для добавления вашего оператора try catch и кода обработки ошибок, как описано во второй ссылке в моем ответе.
Карл,

2
Предоставленная ссылка перемещена: blogs.cozi.com/tech/2008/04/…
natacado

1
Это все еще правда? Я просто попробовал нормальный onerrorподход к работе в Safari + Chrome и, похоже, работает правильно.
Юрий

Ссылка, которую вы дали, почему "этого недостаточно", является довольно старой информацией, и сейчас это не так.
vsync

21

WebKit (Safari, Chrome и т. Д.) Теперь, похоже, поддерживает onerror.

Исходный пост: Насколько я знаю, WebKit / Safari не поддерживает это onerrorсобытие. Это чертовски обидно.


19
Нет, это не так. На вопрос: «А как же Opera и Safari?»
век

То есть, я специально ответил на вопрос, заданный в вопроснике.
век

8
Я думаю, он имел в виду «что [мне делать] с Opera и Safari [у которых нет window.onerror]?»
nickf

10
@nickf, возможно, но если это так, это очень плохо сформулировано, и моя интерпретация в худшем случае понятна и в лучшем случае наиболее вероятна. Это довольно бедна причина для людей , чтобы голосовать мой ответ вниз, особенно с учетом того, что вопрос не утверждать его, и другие читатели могут получить выгоду от положительного или отрицательного утверждения.
Без век

Кажется, теперь Chrome поддерживает это.
Дэниел Икс Мур,

7

На самом деле подход jquery не так уж и плох. Видеть:

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

и:

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

11
для тех, кто это сейчас обнаружит - jquery на самом деле рекомендует не привязывать событие к событию window.error - см. ссылку на документацию выше. Извлечение: обработчик события ошибки jQuery не должен быть прикреплен к объекту окна. [...] Вместо этого используйте window.onerror.
zcrar70

конечно, это не должно быть привязано таким образом, это нелогично! к тому времени, когда это назначение было сделано (если оно было даже успешно выполнено ...) могло произойти много ошибок
vsync

6

Поймайте все исключения своим собственным обработчиком исключений и используйте 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 выдаст собственную ошибку, поскольку нет блока try-catch.

Посетите http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/.


4

try-catchне всегда лучшее решение. Например, в Chrome 7.0 вы теряете красивую трассировку стека в окне консоли. Повторное отображение исключения не помогает. Я не знаю ни одного решения, которое сохраняет следы стека и позволяет вам реагировать на исключение.


2

Немного поработав, можно получить достаточно полные трассировки стека во всех браузерах.

Современные Chrome и Opera (то есть все, что основано на движке рендеринга Blink) полностью поддерживают черновую спецификацию HTML 5 для ErrorEvent и window.onerror. В обоих этих браузерах вы можете либо использовать window.onerror, либо (что удивительно!) Правильно привязать к событию error:

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

К сожалению, Firefox, Safari и IE все еще существуют, и мы тоже должны их поддерживать. Поскольку трассировка стека недоступна, window.onerrorнам нужно проделать еще немного работы.

Оказывается, единственное, что мы можем сделать, чтобы получить трассировку стека ошибок, - это обернуть весь наш код в try{ }catch(e){ }блок, а затем посмотреть на e.stack. Мы можем несколько упростить процесс с помощью функции под названием wrap, которая принимает функцию и возвращает новую функцию с хорошей обработкой ошибок.

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

Это работает. Любая функция, которую вы переносите вручную, будет хорошо обрабатывать ошибки.

Вы можете отправить данные с помощью тега изображения следующим образом

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

Однако вам нужно сделать бэкэнд для сбора данных и внешний интерфейс для визуализации данных.

В Atatus мы работаем над решением этой проблемы. Atatus обеспечивает не только отслеживание ошибок, но и реальный мониторинг пользователей.

Попробуйте https://www.atatus.com/

Отказ от ответственности: я веб-разработчик в Atatus.


1

Это правда, что в современных браузерах перехват window.onerror для ошибок, которые всплывают наверх, вместе с добавлением обработчиков событий jQuery для ошибок Ajax, перехватит практически все объекты Error, добавленные в код вашего клиента. Если вы вручную настраиваете обработчик для window.onerror, в современных браузерах это делается с помощью window.addEventListener('error', callback), а в IE8 / 9 вам нужно вызвать window.attachEvent('onerror', callback).

Обратите внимание, что затем вам следует рассмотреть среду, в которой обрабатываются эти ошибки, и причину этого. Одно дело - поймать как можно больше ошибок с их трассировками стека, но появление современных инструментов разработки F12 решает этот вариант использования при локальной реализации и отладке. Точки останова и т. Д. Предоставят вам больше данных, чем доступно из обработчиков, особенно для ошибок, вызванных сторонними библиотеками, которые были загружены из запросов CORS. Вам необходимо предпринять дополнительные шаги, чтобы указать браузеру предоставить эти данные.

Ключевой проблемой является предоставление этих данных в производственной среде, так как ваши пользователи гарантированно будут запускать гораздо более широкий спектр браузеров и версий, чем вы можете протестировать, и ваш сайт / приложение выйдет из строя неожиданными способами, независимо от того, сколько QA вы бросите. Это.

Чтобы справиться с этим, вам нужен трекер производственных ошибок, который улавливает каждую ошибку, возникшую в браузерах вашего пользователя, когда они используют ваш код, и отправляет их в конечную точку, где вы можете просматривать данные и использовать для исправления ошибок по мере их появления. . В Raygun (отказ от ответственности: я работаю в Raygun) мы приложили кучу усилий, чтобы обеспечить отличный опыт для этого, так как есть много подводных камней и проблем, которые следует учитывать при наивной реализации.

Например, есть вероятность, что вы будете объединять и минимизировать свои ресурсы JS, а это означает, что ошибки, возникающие из минимизированного кода, будут иметь следы нежелательного стека с искаженными именами переменных. Для этого вам понадобится инструмент сборки для генерации исходных карт (мы рекомендуем UglifyJS2 для этой части конвейера) и ваш трекер ошибок, чтобы принимать и обрабатывать их, превращая искаженные трассировки стека обратно в удобочитаемые. Raygun делает все это из коробки и включает конечную точку API для приема исходных карт в том виде, в каком они создаются в процессе сборки. Это ключевой момент, поскольку они не должны быть общедоступными, иначе любой может уничтожить ваш код, отрицая его назначение.

Raygun4js клиентская библиотека также поставляется с window.onerrorдля современных и устаревших браузеров, а также JQuery перехватывает вне коробки, так чтобы установить это вам нужно только добавить:

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

Также имеется множество встроенных функций, включая возможность изменять полезную нагрузку ошибки перед ее отправкой, добавлять теги и пользовательские данные, метаданные о пользователе, который увидел ошибку. Это также облегчает получение хороших трассировок стека из вышеупомянутых сторонних сценариев CORS, которые решают ужасную «ошибку сценария» (которая не содержит сообщений об ошибках и трассировки стека).

Более важная проблема заключается в том, что из-за огромной аудитории в Интернете ваш сайт будет генерировать тысячи повторяющихся экземпляров каждой ошибки. Служба отслеживания ошибок, такая как Raygun , умеет объединять их в группы ошибок, чтобы вы не утонули в потоке уведомлений, и позволяет вам видеть каждую фактическую ошибку, готовую к исправлению.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.