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

Каков наилучший метод для ловли ВСЕХ исключений, брошенных в JavaScript?

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

Я знаю, что браузеры 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.

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

На самом деле подход 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 });
});

Ответ 4

Перехватите все исключения с помощью собственного обработчика исключений и используйте 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/

Ответ 5

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

Ответ 6

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

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

// 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 все еще существуют, и мы также должны их поддерживать. Поскольку stacktrace недоступен в window.onerror, нам нужно немного поработать.

Оказывается, единственное, что мы можем сделать, чтобы получить stacktraces от ошибок, - это обернуть весь наш код в блок 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.

Ответ 7

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

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

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

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

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

Клиентская библиотека raygun4js также поставляется с window.onerror как для современных, так и для устаревших браузеров, а также для перехватчиков jQuery, the-box, поэтому для его установки вам нужно добавить:

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

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

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

Ответ 8

Я также искал обработку ошибок и stacktrace и ведение журнала для действий пользователя, это то, что я нашел, надеюсь, это также поможет вам    https://github.com/jefferyto/glitchjs