推荐答案
前端错误监控主要通过以下几种方式实现:
window.onerror
全局错误捕获:- 监听
window
对象的onerror
事件,可以捕获 JavaScript 运行时错误,包括语法错误和运行时异常。 onerror
事件处理函数接收五个参数:message
(错误信息)、source
(发生错误的脚本 URL)、lineno
(错误行号)、colno
(错误列号)和error
(错误对象)。- 可以将错误信息上报到服务器进行分析和记录。
-- -------------------- ---- ------- -------------- - ----------------- ------- ------- ------ ------ - -- ---------- ------------- -------- -------- ------- ------- ------- ------- ------ ------ ------ ----- - ----------- - ---- -- ---------- --- -- ----------- ------ ----- --
- 监听
try...catch
语句:- 使用
try...catch
语句包裹可能发生错误的代码块,可以捕获代码块内的错误。 - 适用于捕获代码块内部的特定错误,方便根据不同错误情况进行处理。
catch
块中可以获取错误对象,进行错误上报。
-- -------------------- ---- ------- --- - -- --------- ----- --- ----------- -- - ---- -------- - ----- ------- - -- ---------- ------------- -------- -------------- ------ ----------- --- -
- 使用
Promise
的catch
方法:- 对于
Promise
链中的错误,可以使用catch
方法捕获未处理的 rejected 状态。 - 可以将
catch
方法中的错误信息上报。
-- -------------------- ---- ------- ------------------ -------------- -- - ---------------- - ----- --- ----------- ------ ------- -------------------- - ------ --------------- -- ---------- -- - ------ -- ------------ -- - -------- ------------- -------- -------------- ------ ----------- -- --
- 对于
addEventListener
监听unhandledrejection
事件:- 监听
window
对象的unhandledrejection
事件,可以捕获未处理的Promise
rejection。 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
获取。
-- -------------------- ---- ------- ----- --- - --- -------- ------- - ------------- ----------- - --------------- - -- -------- ------------- -------- ------ ---- ------- ------- ---------------- --- --
- 利用
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 等),可以简化错误监控的实现,并提供更完善的错误分析功能。
- 性能影响: 上报错误信息会对性能产生一定影响,需要注意上报频率和数据量,避免影响用户体验。
- 安全考虑: 上报信息中,需要避免泄露用户的敏感信息。