热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CaptureandreportJavaScripterrorswithwindow.onerror

原文:https:blog.sentry.io20160104client-javascript-reporting-window-onerror.htmlonerr

原文:https://blog.sentry.io/2016/01/04/client-Javascript-reporting-window-onerror.html

onerror is a special browser event that fires whenever an uncaught Javascript error has been thrown. It’s one of the easiest ways to log client-side errors and report them to your servers. It’s also one of the major mechanisms by which Sentry’s client Javascript integration (raven-js) works.

You listen to the onerror event by assigning a function to window.onerror:

window.onerror = function (msg, url, lineNo, columnNo, error) { // ... handle error ... return false; }

When an error is thrown, the following arguments are passed to the function:

  • msg – The message associated with the error, e.g. “Uncaught ReferenceError: foo is not defined”
  • url – The URL of the script or document associated with the error, e.g. “/dist/app.js”
  • lineNo – The line number (if available)
  • columnNo – The column number (if available)
  • error – The Error object associated with this error (if available)

The first four arguments tell you in which script, line, and column the error occurred. The final argument, Error object, is perhaps the most valuable. Let’s learn why.

The Error object and error.stack

At first glance the Error object isn’t very special. It contains 3 standardized properties: messagefileName, and lineNumber. Redundant values that already provided to you via window.onerror.

The valuable part is a non-standard property: Error.prototype.stack. This stack property tells you at what source location each frame of the program was when the error occurred. The stack trace can be a critical part of debugging an error. And despite being non-standard, this property is available in every modern browser.

Here’s an example of the Error object’s stack property in Chrome 46:

"Error: foobar\n at new bar (:241:11)\n at foo (:245:5)\n at :250:5\n at :251:3\n at :267:4\n at callFunction (:229:33)\n at :239:23\n at :240:3\n at Object.InjectedScript._evaluateOn (:875:140)\n at Object.InjectedScript._evaluateAndWrap (:808:34)"

Hard to read, right? The stack property is actually just an unformatted string.

Here’s what it looks like formatted:

Error: foobarat new bar (:241:11)at foo (:245:5)at callFunction (:229:33)at Object.InjectedScript._evaluateOn (:875:140)at Object.InjectedScript._evaluateAndWrap (:808:34)

Once it’s been formatted, it’s easy to see how the stack property can be critical in helping to debug an error.

There’s just one snag: the stack property is non-standard, and its implementation differs among browsers. For example, here’s the same stack trace from Internet Explorer 11:

Error: foobarat bar (Unknown script code:2:5)at foo (Unknown script code:6:5)at Anonymous function (Unknown script code:11:5)at Anonymous function (Unknown script code:10:2)at Anonymous function (Unknown script code:1:73)

Not only is the format of each frame different, the frames also have less detail. For example, Chrome identifies that the new keyword has been used, and has greater insight into eval invocations. And this is just IE 11 vs Chrome – other browsers similar have varying formats and detail.

Luckily, there are tools out there that normalize stack properties so that it is consistent across browsers. For example, raven-js uses TraceKit to normalize error strings. There’s also stacktrace.js and a few other projects.

Browser compatibility

window.onerror has been available in browsers for some time – you’ll find it in browsers as old as IE6 and Firefox 2.

The problem is that every browser implements window.onerror differently. Particularly, in how many arguments are sent to to the onerror listener, and the structure of those arguments.

Here’s a table of which arguments are passed to onerror in most browsers:

BrowserMessageURLlineNocolNoerrorObj
Firefox 42
Chrome 46
Android Browser 4.4 
Edge 
IE 11
IE 10 
IE 9, 8  
Safari 9 
iOS 9 

You’ll notice that the latest Apple browsers – Safari and iOS – don’t support a 5th error object argument. And while the final version of Internet Explorer (11) supports the error object, Microsoft’s latest browser, Edge, does not.

Without the error object, there is no stack trace property. This means that these browsers cannot retrieve valuable stack information from errors caught by onerror.

Polyfilling window.onerror with try/catch

But there is a workaround – you can wrap code in your application inside a try/catch and catch the error yourself. This error object will contain our coveted stack property in every modern browser.

Consider the following helper method, invoke, which calls a function on an object with an array of arguments:

function invoke(obj, method, args) { return obj[method].apply(this, args); } invoke(Math, 'max', [1, 2]); // returns 2

Here’s invoke again, this time wrapped in try/catch, in order to capture any thrown error:

function invoke(obj, method, args) { try { return obj[method].apply(this, args); } catch (e) { captureError(e); // report the error throw e; // re-throw the error } } invoke(Math, 'highest', [1, 2]); // throws error, no method Math.highest

Of course, doing this manually everywhere is pretty cumbersome. You can make it easier by creating a generic wrapper utility function:

function wrapErrors(fn) { // don't wrap function more than once if (!fn.__wrapped__) { fn.__wrapped__ = function () { try { return fn.apply(this, arguments); } catch (e) { captureError(e); // report the error throw e; // re-throw the error } }; } return fn.__wrapped__; } var invoke = wrapErrors(function(obj, method, args) { return obj[method].apply(this, args); }); invoke(Math, 'highest', [1, 2]); // no method Math.highest

Because Javascript is single threaded, you don’t need to use wrap everywhere – just at the beginning of every new stack.

That means you’ll need to wrap function declarations:

  • At the start of your application (e.g. in $(document).ready if you use jQuery)
  • In event handlers, e.g. addEventListener or $.fn.click
  • Timer-based callbacks, e.g. setTimeout or requestAnimationFrame

For example:

$(wrapErrors(function () { // application start doSynchronousStuff1(); // doesn't need to be wrapped setTimeout(wrapErrors(function () { doSynchronousStuff2(); // doesn't need to be wrapped }); $('.foo').click(wrapErrors(function () { doSynchronousStuff3(); // doesn't need to be wrapped }); }));

If that seems like a heck of a lot of work, don’t worry! Most error reporting libraries have mechanisms for augmenting built-in functions like addEventListener and setTimeout so that you don’t have to call a wrapping utility every time yourself. And yes, raven-js does this too.

Transmitting the error to your servers

Okay, so you’ve done your job – you’ve plugged into window.onerror, and you’re additionally wrapping functions in try/catch in order to catch as much error information as possible.

There’s just one last step: transmitting the error information to your servers. In order for this to work, you’ll need to set up some kind of reporting web service that will accept your error data over HTTP, log it to a file and/or store it in a database.

If this web service is on the same domain as your web application, this is achieved easily by using XMLHttpRequest. In the example below, we use jQuery’s AJAX function to transmit the data to our servers:

function captureError(ex) { var errorData = { name: ex.name, // e.g. ReferenceError message: ex.line, // e.g. x is undefined url: document.location.href, stack: ex.stack // stacktrace string; remember, different per-browser! }; $.post('/logger/js/', { data: errorData }); }

Note that if you have to transmit your error across different origins, your reporting endpoint will need to support CORS (Cross Origin Resource Sharing).

Summary

If you’ve made it this far, you now have all the tools you need to roll your own basic error reporting library and integrate it with your application:

  • How window.onerror works, and what browsers it supports
  • How to use try/catch to capture stack traces where window.onerror is lacking
  • Transmitting error data to your servers

Of course, if you don’t want to bother with all of this, there are plenty of commercial and open source tools that do all the heavy-lifting of client-side reporting for you. (Psst, you might want to try Sentry.)

That’s it! Happy error hunting.



推荐阅读
  • 利用REM实现移动端布局的高效适配技巧
    在移动设备上实现高效布局适配时,使用rem单位已成为一种流行且有效的技术。本文将分享过去一年中使用rem进行布局适配的经验和心得。rem作为一种相对单位,能够根据根元素的字体大小动态调整,从而确保不同屏幕尺寸下的布局一致性。通过合理设置根元素的字体大小,开发者可以轻松实现响应式设计,提高用户体验。此外,文章还将探讨一些常见的问题和解决方案,帮助开发者更好地掌握这一技术。 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 本文详细探讨了使用纯JavaScript开发经典贪吃蛇游戏的技术细节和实现方法。通过具体的代码示例,深入解析了游戏逻辑、动画效果及用户交互的实现过程,为开发者提供了宝贵的参考和实践经验。 ... [详细]
  • VB.net 进程通信中FindWindow、FindWindowEX、SendMessage函数的理解
    目录一、代码背景二、主要工具三、函数解析1、FindWindow:2、FindWindowEx:3、SendMessage: ... [详细]
  • 双指针法在链表问题中应用广泛,能够高效解决多种经典问题,如合并两个有序链表、合并多个有序链表、查找倒数第k个节点等。本文将详细介绍这些应用场景及其解决方案。 ... [详细]
  • 利用python爬取豆瓣电影Top250的相关信息,包括电影详情链接,图片链接,影片中文名,影片外国名,评分,评价数,概况,导演,主演,年份,地区,类别这12项内容,然后将爬取的信息写入Exce ... [详细]
  • 本文介绍了一种使用 JavaScript 计算两个日期之间时间差的方法。该方法支持多种时间格式,并能返回秒、分钟、小时和天数等不同精度的时间差。 ... [详细]
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 在PHP中如何正确调用JavaScript变量及定义PHP变量的方法详解 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • QT框架中事件循环机制及事件分发类详解
    在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。 ... [详细]
author-avatar
魔术师-文放
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有