推荐答案
前端错误监控主要通过以下几种方式实现:
window.onerror全局错误捕获:- 监听
window对象的onerror事件,可以捕获 JavaScript 运行时错误,包括语法错误和运行时异常。 onerror事件处理函数接收五个参数:message(错误信息)、source(发生错误的脚本 URL)、lineno(错误行号)、colno(错误列号)和error(错误对象)。- 可以将错误信息上报到服务器进行分析和记录。
// www.javascriptcn.com code example window.onerror = function(message, source, lineno, colno, error) { // 上报错误信息到服务器 reportError({ message: message, source: source, lineno: lineno, colno: colno, error: error ? error.stack : null // 尝试获取错误堆栈信息 }); // 阻止浏览器默认错误处理 return true; };- 监听
try...catch语句:- 使用
try...catch语句包裹可能发生错误的代码块,可以捕获代码块内的错误。 - 适用于捕获代码块内部的特定错误,方便根据不同错误情况进行处理。
catch块中可以获取错误对象,进行错误上报。
// www.javascriptcn.com code example try { // 可能发生错误的代码 throw new Error('This is a test error'); } catch (error) { // 上报错误信息到服务器 reportError({ message: error.message, stack: error.stack }); }- 使用
Promise的catch方法:- 对于
Promise链中的错误,可以使用catch方法捕获未处理的 rejected 状态。 - 可以将
catch方法中的错误信息上报。
// www.javascriptcn.com code example fetch('/api/data') .then(response => { if(!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } return response.json() }) .then(data => { //处理数据 }) .catch(error => { //上报错误信息 reportError({ message: error.message, stack: error.stack }) })- 对于
addEventListener监听unhandledrejection事件:- 监听
window对象的unhandledrejection事件,可以捕获未处理的Promiserejection。 unhandledrejection事件处理函数接收一个PromiseRejectionEvent对象,其中reason属性包含拒绝的原因。
window.addEventListener('unhandledrejection', (event) => { // 上报错误信息 reportError({ message: event.reason?.message || 'Unhandled Promise Rejection', stack: event.reason?.stack }); event.preventDefault(); //阻止默认行为 });- 监听
资源加载错误监控:
- 利用
img、script等元素的onerror事件,可以监控资源加载失败的情况。 - 错误信息可以通过
event.target.src获取。
// www.javascriptcn.com code example const img = new Image(); img.src = '/image.jpg'; img.onerror = function(event) { // 上报资源加载错误 reportError({ message: 'Image Load Error', source: event.target.src }); };- 利用
Error对象和堆栈信息:- 错误对象通常包含
message和stack属性,stack属性包含错误堆栈信息,方便定位错误。 - 可以使用
try...catch或onerror获取错误对象。 - 某些情况下,需要考虑不同浏览器中
stack的格式不同,进行统一处理。
- 错误对象通常包含
本题详细解读
为什么需要前端错误监控?
前端错误监控对于维护应用程序的稳定性和用户体验至关重要。 它可以帮助开发者:
- **快速发现问题:**及时发现线上环境中出现的错误,而不是等待用户反馈。
- **定位问题:**通过错误信息、堆栈信息等,快速定位问题代码的位置。
- **优化代码:**分析错误日志,找出代码中的潜在缺陷,持续改进代码质量。
- **提升用户体验:**减少错误发生,避免用户在使用过程中遇到问题,提升用户满意度。
各种错误监控方法的优缺点和适用场景
window.onerror- **优点:**全局捕获,可以捕获大多数 JavaScript 运行时错误,包括语法错误,兼容性好,几乎所有浏览器都支持。
- **缺点:**无法捕获资源加载错误,无法捕获
Promise错误(需要配合unhandledrejection事件),无法精确捕获跨域脚本错误。 - **适用场景:**全局监控,作为错误监控的兜底方案。
try...catch- **优点:**可以捕获代码块内部的错误,方便针对特定错误进行处理,可以捕获同步错误。
- **缺点:**需要手动包裹可能出错的代码,无法捕获异步错误,不能捕获语法错误,可能导致代码冗余。
- **适用场景:**针对性监控,用于捕获已知可能发生错误的代码块。
Promise的catch方法- 优点: 可以捕获异步
Promise错误。 - 缺点: 需要在每个
Promise链中添加catch处理,容易遗漏,不能捕获同步错误。 - 适用场景: 异步操作较多的场景,针对
Promise链的错误处理。
- 优点: 可以捕获异步
addEventListener监听unhandledrejection事件- 优点: 可以捕获
Promise未处理的rejection。 - 缺点: 只能捕获异步
Promise错误,不能捕获同步错误,不是所有浏览器都支持(需要考虑兼容性)。 - 适用场景:
Promise链较多的场景,作为Promise错误的兜底方案。
- 优点: 可以捕获
资源加载错误监控
- 优点: 可以监控资源加载失败,有助于排查资源问题。
- 缺点: 需要针对不同资源类型进行监听,比较繁琐。
- 适用场景: 静态资源较多的场景,如图片,JS 文件,CSS 文件等。
Error对象和堆栈信息- 优点: 堆栈信息可以帮助快速定位错误代码,方便调试。
- 缺点: 不同浏览器
stack格式可能不同,需要进行统一处理,错误对象属性可能不存在,需要做非空判断。 - **适用场景:**所有错误场景,需要尽量获取错误堆栈信息进行上报。
错误上报
- 上报时机: 当错误发生时立即上报。
- 上报方式: 可以通过
XMLHttpRequest、fetch或beacon API上报到服务器。 - 上报内容: 包括错误信息(
message)、错误类型(name)、错误发生的文件(source)、行号(lineno)、列号(colno)、堆栈信息(stack)等,以及用户相关的上下文信息,例如设备、浏览器、用户信息等。 - 错误处理: 错误上报到服务器后,可以进行数据分析、统计、报警等处理。
- 抽样上报: 对于访问量大的应用,可以采取抽样上报,减少上报服务器压力。
- 上报去重: 对于相同的错误,可以进行去重处理,避免重复上报。
如何处理跨域脚本错误
- 对于跨域脚本错误,
window.onerror只能获取有限的错误信息(例如 "Script error.")。 - 为了获取详细的跨域脚本错误信息,需要满足以下条件:
- 跨域资源需要设置
Access-Control-Allow-Origin头部,允许当前域访问。 script标签需要设置crossorigin="anonymous"属性。- 如果资源需要身份验证,需要使用
crossorigin="use-credentials"。
- 跨域资源需要设置
其他需要考虑的点
- Source Maps: 使用 Source Maps 可以将压缩后的代码错误定位到原始代码的位置。
- 错误监控 SDK: 使用现有的错误监控 SDK(如 Sentry、Bugsnag 等),可以简化错误监控的实现,并提供更完善的错误分析功能。
- 性能影响: 上报错误信息会对性能产生一定影响,需要注意上报频率和数据量,避免影响用户体验。
- 安全考虑: 上报信息中,需要避免泄露用户的敏感信息。