Javascript全局error handling
我想捕捉每一个未定义的函数错误抛出。 在Javascript中是否有全局error handling工具? 用例捕获未定义的来自闪存的函数调用。
这是否帮助你:
<script type="text/javascript"> window.onerror = function() { alert("Error caught"); }; xxx(); </script>
我不知道它如何处理Flash错误,但…
更新:它在Opera中不起作用,但我现在正在黑客蜻蜓,看看它是什么。 关于黑客蜻蜓的build议来自这个问题:
模仿窗口。 在Opera中使用JavaScript的onerror
如何抓取未处理的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)有一个未捕获的exception或2)发生编译时错误时,会引发该事件。
未捕获的exception
- 扔“一些消息”
- call_something_undefined();
- cross_origin_iframe.contentWindow.document ;,一个安全exception
编译错误
<script>{</script>
<script>for(;)</script>
<script>"oops</script>
setTimeout("{", 10);
它会尝试将第一个参数编译为脚本
支持window.onerror的浏览器
- Chrome 13+
- Firefox 6.0+
- Internet Explorer 5.5+
- Opera 11.60以上
- Safari 5.1+
截图:
添加到testing页后,上面的onerror代码示例:
<script type="text/javascript"> call_something_undefined(); </script>
的jsfiddle:
https://jsfiddle.net/nzfvm44d/
参考文献:
- Mozilla开发者networking:: window.onerror
- MSDN ::处理和避免网页错误第2部分:运行时错误
- 回到基础 – JavaScript onerror事件
- DEV.OPERA ::更好的error handling与window.onerror
- Window on Error事件
- 使用onerror事件来抑制JavaScript错误
- SO :: window.onerror不能在Firefox中触发
复杂的error handling
如果你的error handling是非常复杂的,所以可能会自己抛出一个错误,添加一个标志表示你是否已经处于“errorHandling-Mode”状态。 像这样:
var appIsHandlingError = false; window.onerror = function() { if (!appIsHandlingError) { appIsHandlingError = true; handleError(); } }; function handleError() { // graceful error handling // if successful: appIsHandlingError = false; }
否则,你会发现自己在一个无限循环。
试用Atatus为现代networking应用程序提供高级错误跟踪和真实用户监控。
让我解释一下如何获得在所有浏览器中合理完成的堆栈跟踪。
在JavaScript中处理错误
现代的Chrome和Opera完全支持ErrorEvent和window.onerror
的HTML 5草案规范。 在这两种浏览器中,您都可以使用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
没有可用的堆栈跟踪,我们必须做更多的工作。
事实certificate,我们唯一能做的就是将所有的代码包装在一个try{ }catch(e){ }
块中,然后看看e.stack
。 我们可以通过一个叫wrap的函数来简化这个过程,这个函数接受一个函数并返回一个新的函数,并且具有良好的error handling能力
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; };
这工作。 你手动包装的任何函数都会有很好的error handling,但事实certificate,在大多数情况下,我们实际上可以为你自动完成。
通过改变addEventListener
的全局定义,使其自动包装callback,我们可以在大多数代码中自动插入try{ }catch(e){ }
。 这使现有的代码继续工作,但增加了高质量的exception跟踪。
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; }
免责声明:我是一个Web开发人员在https://www.atatus.com/ 。
看来, window.onerror
不提供访问所有可能的错误。 具体而言,它忽略了:
-
<img>
加载错误(response> = 400)。 -
<script>
加载错误(response> = 400)。 - 全局错误,如果你的应用程序中还有许多其他的库也以未知的方式操纵
window.onerror
(jQuery,angular等)。 - 可能很多情况下,我没有遇到现在探索这个(iframes,堆栈溢出等)。
这是一个捕捉这些错误的脚本的开始,以便您可以在开发过程中为您的应用程序添加更强大的debuggingfunction。
(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://stackoverflow.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; } } } } /** * 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://stackoverflow.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); };
完整的脚本有一个默认的实现,试图打印出它接收到的实体/错误的半可读“显示”版本。 可以用于灵感的应用程序特定的error handling程序。 默认实现还保留对最后100个错误实体的引用,因此您可以在Web控制台中检查它们,例如:
window.onanyerror0 window.onanyerror1 ... window.onanyerror99
注意:这通过覆盖几个浏览器/本地构造函数的方法来工作。 这可能会产生意想不到的副作用。 但是,在开发过程中使用这个函数是很有用的,可以找出发生错误的位置,在开发过程中将日志发送到NewRelic或Sentry等服务,这样我们可以在开发过程中测量错误,更深层次。 它可以在生产中closures。
希望这可以帮助。
// 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;
我会build议给Trackjs一个尝试。
这是错误日志logging服务。
这是非常简单的设置。 只需添加一个<script>行到每一页,就是这样。 这也意味着,如果你决定不喜欢它,它将是非常简单的删除。
还有其他一些服务,如Sentry (如果你可以托pipe你自己的服务器,它是开源的),但是它并没有像Trackjs那样做。 Trackjslogging用户在浏览器和你的networking服务器之间的交互,这样你就可以实际追踪导致错误的用户步骤,而不仅仅是文件和行号参考(也可能是堆栈跟踪)。
我们也应该保留之前关联的onerrorcallback
<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之外还有一个未处理的拒绝。
通过给window.onerror分配一个函数来监听onerror事件:
window.onerror = function (msg, url, lineNo, columnNo, error) { var string = msg.toLowerCase(); var substring = "script error"; if (string.indexOf(substring) > -1){ alert('Script Error: See Browser Console for Detail'); } else { alert(msg, url, lineNo, columnNo, error); } return false; };