核心要点
window.onerror
是一个浏览器事件,在抛出未捕获的 JavaScript 错误时触发,提供了一种简单的记录客户端错误并将其报告到服务器的方法。所有现代浏览器都支持此事件,但实现细节有所不同。window.onerror
的 Error 对象对于调试非常有价值,因为它包含错误堆栈跟踪,该跟踪提供了程序出错时每个帧的源位置。但是,stack 属性是非标准的,其在不同浏览器中的实现方式也不同。window.onerror
广泛支持,但并非所有浏览器都传递 Error 对象,这意味着它们无法检索 stack 跟踪属性。可以通过将代码包装在 try/catch 块中来解决此限制,以捕获错误及其 stack 属性。本文与 Sentry 合作创作。感谢您支持使 SitePoint 成为可能的合作伙伴。
window.onerror
是一个特殊的浏览器事件,每当抛出未捕获的 JavaScript 错误时就会触发。它是记录客户端错误并将其报告到服务器的最简单方法之一。这也是 Sentry 的客户端 JavaScript 集成 (raven-js) 工作的主要机制之一。
通过将函数分配给 window.onerror
来监听 onerror
事件:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
抛出错误时,以下参数将传递给函数:
msg
– 与错误关联的消息,例如“Uncaught ReferenceError: foo is not defined”url
– 与错误关联的脚本或文档的 URL,例如“/dist/app.js”lineNo
– 行号(如果可用)columnNo
– 列号(如果可用)error
– 与此错误关联的 Error 对象(如果可用)前四个参数告诉您错误发生在哪个脚本、行和列中。最后一个参数,Error 对象,也许是最有价值的。让我们了解原因。
Error 对象和 error.stack
乍一看,Error 对象并不特别。它包含 3 个标准化属性:message、fileName 和 lineNumber。这些冗余值已通过 window.onerror
提供给您。
有价值的部分是一个非标准属性:Error.prototype.stack
。此 stack 属性告诉您程序出错时每个程序帧的源位置。错误堆栈跟踪可能是调试的关键部分。尽管是非标准的,但此属性在每个现代浏览器中都可用。
以下是 Chrome 46 中 Error 对象的 stack 属性示例:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
难以阅读,对吧?stack 属性实际上只是一个未格式化的字符串。
以下是格式化后的样子:
<code>"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript._evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)" </anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></code>
格式化后,很容易看出 stack 属性如何在帮助调试错误方面至关重要。
只有一个问题:stack 属性是非标准的,其在不同浏览器中的实现方式也不同。例如,以下是 Internet Explorer 11 中的相同堆栈跟踪:
<code>Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34) </anonymous></anonymous></anonymous></anonymous></anonymous></code>
每个帧的格式不仅不同,帧的细节也更少。例如,Chrome 识别已使用 new 关键字,并且对 eval 调用有更深入的了解。这只是 IE 11 与 Chrome 的比较——其他浏览器也类似地具有不同的格式和细节。
幸运的是,有一些工具可以规范化 stack 属性,使其在不同浏览器中保持一致。例如,raven-js 使用 TraceKit 来规范化错误字符串。还有 stacktrace.js 和其他一些项目。
浏览器兼容性
window.onerror
在浏览器中已经存在一段时间了——您可以在 IE6 和 Firefox 2 等旧版浏览器中找到它。
问题是每个浏览器都以不同的方式实现 window.onerror
,尤其是在发送到 onerror 侦听器的参数数量和这些参数的结构方面。
以下是大多数浏览器中传递给 onerror 的参数的表格:
浏览器 | Message | URL | lineNo | colNo | errorObj |
---|---|---|---|---|---|
Firefox | ✓ | ✓ | ✓ | ✓ | ✓ |
Chrome | ✓ | ✓ | ✓ | ✓ | ✓ |
Edge | ✓ | ✓ | ✓ | ✓ | ✓ |
IE 11 | ✓ | ✓ | ✓ | ✓ | ✓ |
IE 10 | ✓ | ✓ | ✓ | ✓ | |
IE 9, 8 | ✓ | ✓ | ✓ | ||
Safari 10 及以上 | ✓ | ✓ | ✓ | ✓ | ✓ |
Safari 9 | ✓ | ✓ | ✓ | ✓ | |
Android 浏览器 4.4 | ✓ | ✓ | ✓ | ✓ |
Internet Explorer 8、9 和 10 对 onerror
的支持有限,这可能并不令人意外。但您可能会惊讶地发现,Safari 直到 Safari 10(于 2016 年发布)才添加对 error 对象的支持。此外,仍然使用库存 Android 浏览器(现已替换为 Chrome Mobile)的旧版移动设备仍然存在,并且不会传递 error 对象。
如果没有 error 对象,就没有 stack 跟踪属性。这意味着这些浏览器无法从 onerror
捕获的错误中检索有价值的堆栈信息。
使用 try/catch 为 window.onerror 提供 polyfill
但是有一个解决方法——您可以将应用程序中的代码包装在 try/catch 块中,并自行捕获错误。此 error 对象将在每个现代浏览器中包含我们梦寐以求的 stack 属性。
考虑以下辅助方法 invoke
,它使用一系列参数在对象上调用函数:
window.onerror = function (msg, url, lineNo, columnNo, error) { // ... 处理错误 ... return false; }
以下是再次调用的 invoke
,这次包装在 try/catch 中,以便捕获任何抛出的错误:
<code>"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript._evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)" </anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></code>
当然,在任何地方手动执行此操作都非常麻烦。您可以通过创建通用的包装器实用程序函数来简化它:
<code>Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34) </anonymous></anonymous></anonymous></anonymous></anonymous></code>
因为 JavaScript 是单线程的,所以您不需要在任何地方都使用包装器——只需在每个新堆栈的开头即可。
这意味着您需要包装函数声明:
$(document).ready
中)addEventListener
或 $.fn.click
)setTimeout
或 requestAnimationFrame
)例如:
<code>Error: foobar at 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)</code>
如果这看起来像很多工作,别担心!大多数错误报告库都有增强内置函数(如 addEventListener
和 setTimeout
)的机制,因此您不必每次都自己调用包装实用程序。是的,raven-js 也这样做。
将错误传输到服务器
好的,您已经完成了您的工作——您已经插入了 window.onerror
,并且您还将函数包装在 try/catch 块中,以便捕获尽可能多的错误信息。
只剩最后一步:将错误信息传输到服务器。为了使这能够工作,您需要设置某种报告 Web 服务,该服务将通过 HTTP 接收您的错误数据,将其记录到文件和/或存储到数据库中。
如果此 Web 服务与您的 Web 应用程序位于同一域,则只需使用 XMLHttpRequest。在下面的示例中,我们使用 jQuery 的 AJAX 函数将数据传输到我们的服务器:
function invoke(obj, method, args) { return obj[method].apply(this, args); } invoke(Math, 'max', [1, 2]); // 返回 2
请注意,如果您必须跨不同来源传输错误,则您的报告端点需要支持跨域资源共享 (CORS)。
总结
如果您已经完成了这一步,那么您现在拥有了所有必要的工具来滚动您自己的基本错误报告库并将其与您的应用程序集成:
window.onerror
的工作原理及其支持的浏览器window.onerror
缺少的堆栈跟踪当然,如果您不想费心处理所有这些,有很多商业和开源工具可以为您完成客户端报告的所有繁重工作。(嘘:您可能想尝试使用 Sentry 来调试 JavaScript。)
就是这样!祝您错误监控愉快。
关于使用 window.onerror 捕获和报告 JavaScript 错误的常见问题解答 (FAQ)
window.onerror
函数在 JavaScript 中是如何工作的?JavaScript 中的 window.onerror
事件是一个全局事件处理程序,当执行 JavaScript 代码时发生错误时会触发。它是一个强大的调试和错误处理工具,因为它可以捕获和报告未捕获的异常或运行时错误。当发生错误时,window.onerror
函数将使用五个参数调用:错误消息、发生错误的 URL、行号、列号和 Error 对象。
window.onerror
和 try-catch 之间的区别是什么?window.onerror
和 try-catch 都用于 JavaScript 中的错误处理,但它们的工作方式不同。try-catch 语句允许您通过将可能引发错误的代码包装在 try 块中,然后在 catch 块中响应错误来直接处理错误。另一方面,window.onerror
是一个全局事件处理程序,当发生未捕获的运行时错误时会触发。它是一种更通用的错误处理机制,可以捕获从 try-catch 块中溜走的错误。
window.onerror
捕获 JavaScript 错误?要使用 window.onerror
,您需要定义一个函数,当发生错误时将调用该函数。此函数应采用五个参数:错误消息、发生错误的 URL、行号、列号和 Error 对象。在此函数内部,您可以根据需要处理错误。例如,您可以将错误记录到控制台、向服务器发送报告或向用户显示消息。
window.onerror
可以捕获所有类型的 JavaScript 错误吗?虽然 window.onerror
是一个强大的错误处理工具,但它确实有一些限制。它可以捕获大多数未捕获的运行时错误,但它无法捕获在 try-catch 块中抛出和捕获的异常。此外,某些类型的错误(例如网络错误或 CORS 错误)可能不会触发 window.onerror
事件。
window.onerror
中使用 Error 对象?Error 对象是传递给 window.onerror
函数的第五个参数。它包含有关发生错误的信息,包括错误消息、错误名称和堆栈跟踪。您可以使用此对象来获取有关错误的更详细信息,这对于调试或错误报告非常有用。
堆栈跟踪是一个报告,提供有关错误发生时程序执行路径的信息。它显示导致错误的函数调用序列,这对于调试非常有用。在 JavaScript 中,您可以从 Error 对象获取堆栈跟踪。
在 JavaScript 中,您可以从 Error 对象获取堆栈跟踪。当发生错误时,会创建一个 Error 对象并将其传递给 window.onerror
函数。此对象有一个名为 stack 的属性,其中包含堆栈跟踪。您可以访问此属性以获取堆栈跟踪。
window.onerror
将错误报告到服务器吗?是的,您可以使用 window.onerror
将错误报告到服务器。在您的 window.onerror
函数内部,您可以向服务器发送包含错误信息的请求。这对于监控和调试非常有用,因为它允许您实时收集和分析来自用户的错误数据。
window.onerror
处理 CORS 错误?CORS 错误或跨域资源共享错误发生在 Web 应用程序尝试访问来自不同域的资源时。这些错误与安全相关,并且由于安全原因,不会向 window.onerror
事件处理程序提供详细信息。但是,您可以通过向可能导致 CORS 错误的特定网络请求添加错误处理程序来处理这些错误。
window.onerror
的一些最佳实践是什么?使用 window.onerror
时,务必以不会中断用户体验的方式处理错误。您应该避免向用户显示技术错误消息。相反,请考虑显示友好的错误消息或静默记录错误。此外,请注意错误处理代码的性能影响。例如,如果您要将错误报告发送到服务器,请确保异步执行此操作,以免阻塞主线程。
以上是用窗口捕获和报告JavaScript错误。的详细内容。更多信息请关注PHP中文网其他相关文章!