Обработка исключений 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