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> 

显示由window.onerror事件详述的错误信息的Javascript警报

的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应用程序提供高级错误跟踪和真实用户监控。

https://www.atatus.com/

让我解释一下如何获得在所有浏览器中合理完成的堆栈跟踪。

在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不提供访问所有可能的错误。 具体而言,它忽略了:

  1. <img>加载错误(response> = 400)。
  2. <script>加载错误(response> = 400)。
  3. 全局错误,如果你的应用程序中还有许多其他的库也以未知的方式操纵window.onerror (jQuery,angular等)。
  4. 可能很多情况下,我没有遇到现在探索这个(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; };