JavaScript глобальная обработка ошибок
Я хотел бы поймать каждую неопределенную ошибку в функции. Есть ли глобальная возможность обработки ошибок в JavaScript? Вариант использования - перехват вызовов функций из флэш-памяти, которые не определены.
10 ответов
Помогает ли это вам:
<script type="text/javascript">
window.onerror = function() {
alert("Error caught");
};
xxx();
</script>
Я не уверен, как он обрабатывает ошибки Flash, хотя...
Обновление: в Opera это не работает, но я сейчас взламываю Dragonfly, чтобы посмотреть, что получится. Предложение о взломе Dragonfly пришло из этого вопроса:
Как поймать необработанные ошибки Javascript
Назначьте window.onerror
событие для обработчика события, например:
<script type="text/javascript">
window.onerror = function(msg, url, line, col, error) {
// Note that col & error are new to the HTML 5 spec and may not be
// supported in every browser. It worked for me in Chrome.
var extra = !col ? '' : '\ncolumn: ' + col;
extra += !error ? '' : '\nerror: ' + error;
// You can view the information in an alert to see things working like this:
alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);
// TODO: Report this error via ajax so you can keep track
// of what pages have JS issues
var suppressErrorAlert = true;
// If you return true, then error alerts (like in older versions of
// Internet Explorer) will be suppressed.
return suppressErrorAlert;
};
</script>
Как прокомментировано в коде, если возвращаемое значение window.onerror
является true
тогда браузер должен отключить отображение диалогового окна с предупреждением.
Когда срабатывает событие window.onerror?
В двух словах, событие возникает, когда либо 1.) существует неперехваченное исключение, либо 2.) происходит ошибка времени компиляции.
неучтенные исключения
- киньте "некоторые сообщения"
- call_something_undefined ();
- cross_origin_iframe.contentWindow.document;, исключение безопасности
ошибка компиляции
<script>{</script>
<script>for(;)</script>
<script>"oops</script>
setTimeout("{", 10);
, он попытается скомпилировать первый аргумент как скрипт
Браузеры, поддерживающие window.onerror
- Chrome 13+
- Firefox 6.0+
- Internet Explorer 5.5+
- Опера 11.60+
- Safari 5.1+
Скриншот:
Пример приведенного выше кода ошибки в действии после добавления этого на тестовую страницу:
<script type="text/javascript">
call_something_undefined();
</script>
JSFiddle:
https://jsfiddle.net/nzfvm44d/
Рекомендации:
- Сеть разработчиков Mozilla:: window.onerror
- MSDN:: Обработка и предотвращение ошибок веб-страниц. Часть 2. Ошибки времени выполнения
- Вернуться к основам - JavaScript событие onerror
- DEV.OPERA:: Лучшая обработка ошибок с помощью window.onerror
- Окно onError Event
- Использование события onerror для подавления ошибок JavaScript
- SO:: window.onerror не запускается в Firefox
сложная обработка ошибок
Если ваша обработка ошибок очень сложна и, следовательно, может выдать саму ошибку, полезно добавить флаг, указывающий, что вы уже находитесь в "errorHandling-Mode". Вот так:
var appIsHandlingError = false;
window.onerror = function() {
if (!appIsHandlingError) {
appIsHandlingError = true;
handleError();
}
};
function handleError() {
// graceful error handling
// if successful: appIsHandlingError = false;
}
В противном случае вы можете оказаться в бесконечном цикле.
Кажется, что window.onerror
не предоставляет доступ ко всем возможным ошибкам. В частности, он игнорирует:
<img>
ошибки загрузки (ответ>= 400).<script>
ошибки загрузки (ответ>= 400).- глобальные ошибки, если у вас есть много других библиотек в вашем приложении, также манипулирующих
window.onerror
неизвестным образом (jquery, угловой и т. д.). - вероятно, во многих случаях, с которыми я не сталкивался после изучения этого сейчас (iframes, переполнение стека и т. д.).
Вот начало сценария, который улавливает многие из этих ошибок, так что вы можете добавить более надежную отладку в ваше приложение во время разработки.
(function(){
/**
* Capture error data for debugging in web console.
*/
var captures = [];
/**
* Wait until `window.onload`, so any external scripts
* you might load have a chance to set their own error handlers,
* which we don't want to override.
*/
window.addEventListener('load', onload);
/**
* Custom global function to standardize
* window.onerror so it works like you'd think.
*
* @see http://www.quirksmode.org/dom/events/error.html
*/
window.onanyerror = window.onanyerror || onanyerrorx;
/**
* Hook up all error handlers after window loads.
*/
function onload() {
handleGlobal();
handleXMLHttp();
handleImage();
handleScript();
handleEvents();
}
/**
* Handle global window events.
*/
function handleGlobal() {
var onerrorx = window.onerror;
window.addEventListener('error', onerror);
function onerror(msg, url, line, col, error) {
window.onanyerror.apply(this, arguments);
if (onerrorx) return onerrorx.apply(null, arguments);
}
}
/**
* Handle ajax request errors.
*/
function handleXMLHttp() {
var sendx = XMLHttpRequest.prototype.send;
window.XMLHttpRequest.prototype.send = function(){
handleAsync(this);
return sendx.apply(this, arguments);
};
}
/**
* Handle image errors.
*/
function handleImage() {
var ImageOriginal = window.Image;
window.Image = ImageOverride;
/**
* New `Image` constructor. Might cause some problems,
* but not sure yet. This is at least a start, and works on chrome.
*/
function ImageOverride() {
var img = new ImageOriginal;
onnext(function(){ handleAsync(img); });
return img;
}
}
/**
* Handle script errors.
*/
function handleScript() {
var HTMLScriptElementOriginal = window.HTMLScriptElement;
window.HTMLScriptElement = HTMLScriptElementOverride;
/**
* New `HTMLScriptElement` constructor.
*
* Allows us to globally override onload.
* Not ideal to override stuff, but it helps with debugging.
*/
function HTMLScriptElementOverride() {
var script = new HTMLScriptElement;
onnext(function(){ handleAsync(script); });
return script;
}
}
/**
* Handle errors in events.
*
* @see http://stackru.com/questions/951791/javascript-global-error-handling/31750604#31750604
*/
function handleEvents() {
var addEventListenerx = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = addEventListener;
var removeEventListenerx = window.EventTarget.prototype.removeEventListener;
window.EventTarget.prototype.removeEventListener = removeEventListener;
function addEventListener(event, handler, bubble) {
var handlerx = wrap(handler);
return addEventListenerx.call(this, event, handlerx, bubble);
}
function removeEventListener(event, handler, bubble) {
handler = handler._witherror || handler;
removeEventListenerx.call(this, event, handler, bubble);
}
function wrap(fn) {
fn._witherror = witherror;
function witherror() {
try {
fn.apply(this, arguments);
} catch(e) {
window.onanyerror.apply(this, e);
throw e;
}
}
return fn;
}
}
/**
* Handle image/ajax request errors generically.
*/
function handleAsync(obj) {
var onerrorx = obj.onerror;
obj.onerror = onerror;
var onabortx = obj.onabort;
obj.onabort = onabort;
var onloadx = obj.onload;
obj.onload = onload;
/**
* Handle `onerror`.
*/
function onerror(error) {
window.onanyerror.call(this, error);
if (onerrorx) return onerrorx.apply(this, arguments);
};
/**
* Handle `onabort`.
*/
function onabort(error) {
window.onanyerror.call(this, error);
if (onabortx) return onabortx.apply(this, arguments);
};
/**
* Handle `onload`.
*
* For images, you can get a 403 response error,
* but this isn't triggered as a global on error.
* This sort of standardizes it.
*
* "there is no way to get the HTTP status from a
* request made by an img tag in JavaScript."
* @see http://stackru.com/questions/8108636/how-to-get-http-status-code-of-img-tags/8108646#8108646
*/
function onload(request) {
if (request.status && request.status >= 400) {
window.onanyerror.call(this, request);
}
if (onloadx) return onloadx.apply(this, arguments);
}
}
/**
* Generic error handler.
*
* This shows the basic implementation,
* which you could override in your app.
*/
function onanyerrorx(entity) {
var display = entity;
// ajax request
if (entity instanceof XMLHttpRequest) {
// 400: http://example.com/image.png
display = entity.status + ' ' + entity.responseURL;
} else if (entity instanceof Event) {
// global window events, or image events
var target = entity.currentTarget;
display = target;
} else {
// not sure if there are others
}
capture(entity);
console.log('[onanyerror]', display, entity);
}
/**
* Capture stuff for debugging purposes.
*
* Keep them in memory so you can reference them
* in the chrome debugger as `onanyerror0` up to `onanyerror99`.
*/
function capture(entity) {
captures.push(entity);
if (captures.length > 100) captures.unshift();
// keep the last ones around
var i = captures.length;
while (--i) {
var x = captures[i];
window['onanyerror' + i] = x;
}
}
/**
* Wait til next code execution cycle as fast as possible.
*/
function onnext(fn) {
setTimeout(fn, 0);
}
})();
Это можно использовать так:
window.onanyerror = function(entity){
console.log('some error', entity);
};
Полный сценарий имеет реализацию по умолчанию, которая пытается распечатать получитаемую "отображаемую" версию объекта / ошибки, которую он получает. Может быть использован для вдохновения для обработчика ошибок для конкретного приложения. Реализация по умолчанию также сохраняет ссылку на последние 100 объектов ошибок, поэтому вы можете просмотреть их в веб-консоли после того, как они произошли, например:
window.onanyerror0
window.onanyerror1
...
window.onanyerror99
Примечание. Это работает путем переопределения методов в нескольких браузерах / собственных конструкторах. Это может иметь непредвиденные побочные эффекты. Тем не менее, это было полезно использовать во время разработки, чтобы выяснить, где происходят ошибки, для отправки журналов в сервисы, такие как NewRelic или Sentry, во время разработки, чтобы мы могли измерять ошибки во время разработки и при подготовке, чтобы мы могли отлаживать то, что происходит в более глубокий уровень. Затем он может быть отключен в производстве.
Надеюсь это поможет.
Попробуйте Atatus, который обеспечивает расширенное отслеживание ошибок и мониторинг реальных пользователей для современных веб-приложений.
Позвольте мне объяснить, как получить трассировки стека, которые достаточно полны во всех браузерах.
Обработка ошибок в JavaScript
Современные Chrome и Opera полностью поддерживают проект спецификации 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
// sendError(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
// sendError(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
// sendError(data);
throw e;
}
}
}
return func._wrapped;
};
Это работает. Любая функция, которую вы переносите вручную, будет иметь хорошую обработку ошибок, но в большинстве случаев оказывается, что мы можем сделать это автоматически.
Изменяя глобальное определение addEventListener
так что он автоматически оборачивает обратный вызов, мы можем автоматически вставить try{ }catch(e){ }
вокруг самого кода. Это позволяет существующему коду продолжать работать, но добавляет высококачественное отслеживание исключений.
var addEventListener = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
addEventListener.call(this, event, wrap(callback), bubble);
}
Мы также должны убедиться, что removeEventListener
продолжает работать. На данный момент это не так, потому что аргумент addEventListener
изменено Опять же, нам нужно только исправить это на prototype
объект:
var removeEventListener = window.EventTarget.prototype.removeEventListener;
window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
removeEventListener.call(this, event, callback._wrapped || callback, bubble);
}
Передайте данные об ошибках в свой бэкэнд
Вы можете отправить данные об ошибке с помощью тега изображения следующим образом
function sendError(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;
}
Отказ от ответственности: я веб-разработчик на https://www.atatus.com/.
// display error messages for a page, but never more than 3 errors
window.onerror = function(msg, url, line) {
if (onerror.num++ < onerror.max) {
alert("ERROR: " + msg + "\n" + url + ":" + line);
return true;
}
}
onerror.max = 3;
onerror.num = 0;
Следует также сохранить ранее связанный обратный вызов onerror
<script type="text/javascript">
(function() {
var errorCallback = window.onerror;
window.onerror = function () {
// handle error condition
errorCallback && errorCallback.apply(this, arguments);
};
})();
</script>
Если вам нужен унифицированный способ обработки как необработанных ошибок, так и необработанных отклонений обещаний, вы можете взглянуть на необработанную библиотеку.
РЕДАКТИРОВАТЬ
<script type="text/javascript" src=".../uncaught/lib/index.js"></script>
<script type="text/javascript">
uncaught.start();
uncaught.addListener(function (error) {
console.log('Uncaught error or rejection: ', error.message);
});
</script>
Слушает окно. необработанный отказ в дополнение к window.onerror.
Я бы порекомендовал дать Trackjs попробовать.
Это регистрация ошибок как сервис.
Это удивительно просто настроить. Просто добавьте одну строку