前端错误监控
常见错误类型
| 错误 | 解释 | 示例 | | -------------- | -------------------------- | ------------------------------------ | | SyntaxError | 解析时发生语法错误 | const x | | TypeError | 值不是所期待的类型 | const person = 1; person.name | | ReferenceError | 引用未声明的变量 | x | | RangeError | 一个值不在其所允许的范围中 | new Array(-1) | | ResourceError | 资源加载错误 | new Image().src = '/remote/null.jpg' | | HttpError | http 请求错误 | fetch('/remote/null') |
如何捕获错误
try/catch
能够捕获常规运行时错误,语法错误和异步错误无法捕获
1// 常规运行时错误,可以捕获 ✅
2try {
3 console.log(notdefined);
4} catch(e) {
5 console.log('捕获到异常:', e);
6}
7
8// 语法错误,不能捕获 ❌
9try {
10 const notdefined,
11} catch(e) {
12 console.log('捕获到异常:', e);
13}
14
15// 异步错误,不能捕获 ❌
16try {
17 setTimeout(() => {
18 console.log(notdefined);
19 }, 0)
20} catch(e) {
21 console.log('捕获到异常:',e);
22}
23window.onerror
混合事件 GlobalEventHandlers 的 onerror 属性是用于处理 error 的事件 Error 事件的事件处理程序,在各种目标对象的不同类型错误被触发:
- 当 JavaScript 运行时错误(包括语法错误)发生时,window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()。
- 当一项资源(如<img>或<script>)加载失败,加载资源的元素会触发一个 Event 接口的 error 事件,并执行该元素上的 onerror() 处理函数。这些 error 事件不会向上冒泡到 window,不过(至少在 Firefox 中)能被单一的 window.addEventListener 捕获。
1window.onerror = function(message, source, lineno, colno, error) { ... }函数参数:
- message:错误信息(字符串)。可用于 HTML onerror=""处理程序中的 event。
- source:发生错误的脚本 URL(字符串)
- lineno:发生错误的行号(数字)
- colno:发生错误的列号(数字)
- error:Error 对象(对象)
若该函数返回 true,则阻止执行默认事件处理函数。
1// 常规运行时错误,可以捕获 ✅
2window.onerror = function(message, source, lineno, colno, error) {
3 console.log('捕获到异常:',{message, source, lineno, colno, error});
4}
5console.log(notdefined);
6
7// 语法错误,不能捕获 ❌
8window.onerror = function(message, source, lineno, colno, error) {
9 console.log('捕获到异常:',{message, source, lineno, colno, error});
10}
11const notdefined,
12
13// 异步错误,可以捕获 ✅
14window.onerror = function(message, source, lineno, colno, error) {
15 console.log('捕获到异常:',{message, source, lineno, colno, error});
16}
17setTimeout(() => {
18 console.log(notdefined);
19}, 0)
20
21// 资源错误,不能捕获 ❌
22<script>
23 window.onerror = function(message, source, lineno, colno, error) {
24 console.log('捕获到异常:',{message, source, lineno, colno, error});
25 return true;
26}
27</script>
28<img src="https://unknown/image/null.png">
29window.addEventListener
1// 图片、script、css加载错误,都能被捕获 ✅
2<script>
3 window.addEventListener(
4 'error',
5 (error) => {
6 console.log('捕获到异常:', error)
7 },
8 true,
9 )
10</script>
11<img src="https://unknown/image/null.png" />
12<script src="https://unknown/foundnull.js"></script>
13<link href="https://unknown/foundnull.css" rel="stylesheet" />
14
15// new Image错误,不能捕获 ❌
16<script>
17 window.addEventListener(
18 'error',
19 (error) => {
20 console.log('捕获到异常:', error)
21 },
22 true,
23 )
24</script>
25<script>
26 new Image().src = 'https://unknown/image/null.png'
27</script>
28
29// fetch错误,不能捕获 ❌
30<script>
31 window.addEventListener(
32 'error',
33 (error) => {
34 console.log('捕获到异常:', error)
35 },
36 true,
37 )
38</script>
39<script>
40 fetch('https://unknown/test')
41</script>异步错误
如果使用 try/catch 能捕获 await 的错误 普通 Promise 错误 使用 catch
全局捕获错误 - unhandledrejection
1// 全局统一处理Promise
2window.addEventListener('unhandledrejection', function (e) {
3 console.log('捕获到异常:', e)
4})
5fetch('https://unknown/test')Vue 的错误
vue 的错误会被 vue 自动捕获,并且抛给 Vue.config.errorHandler。
1/**
2 * 全局捕获Vue错误,直接扔出给onerror处理
3 */
4Vue.config.errorHandler = function (err) {
5 setTimeout(() => {
6 throw err
7 })
8}React 错误
react 通过 componentDidCatch,声明一个错误边界的组件
数据上报接口
使用 1*1 像素的 gif 图片进行上报,有以下几点好处
- 不会阻塞页面渲染
- 图片天然跨域
- 不会携带 Cookie
- 不需等待服务器返回数据
- gif 图片所需流量最小
但数据太大,最好还是用 post