文章

前端错误监控

前端错误监控

常见错误类型

错误解释示例
SyntaxError解析时发生语法错误const x
TypeError值不是所期待的类型const person = 1; person.name
ReferenceError引用未声明的变量x
RangeError一个值不在其所允许的范围中new Array(-1)
ResourceError资源加载错误new Image().src = ‘/remote/null.jpg’
HttpErrorhttp 请求错误fetch(‘/remote/null’)

如何捕获错误

try/catch

能够捕获常规运行时错误,语法错误和异步错误无法捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 常规运行时错误,可以捕获 ✅
try {
  console.log(notdefined);
} catch(e) {
  console.log('捕获到异常:', e);
}

// 语法错误,不能捕获 ❌
try {
  const notdefined,
} catch(e) {
  console.log('捕获到异常:', e);
}

// 异步错误,不能捕获 ❌
try {
  setTimeout(() => {
    console.log(notdefined);
  }, 0)
} catch(e) {
  console.log('捕获到异常:',e);
}

window.onerror

混合事件 GlobalEventHandlers 的 onerror 属性是用于处理 error 的事件 Error 事件的事件处理程序,在各种目标对象的不同类型错误被触发:

  • 当 JavaScript 运行时错误(包括语法错误)发生时,window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()。
  • 当一项资源(如<img>或<script>)加载失败,加载资源的元素会触发一个 Event 接口的 error 事件,并执行该元素上的 onerror() 处理函数。这些 error 事件不会向上冒泡到 window,不过(至少在 Firefox 中)能被单一的 window.addEventListener 捕获。
1
window.onerror = function(message, source, lineno, colno, error) { ... }

函数参数:

  • message:错误信息(字符串)。可用于 HTML onerror=”“处理程序中的 event。
  • source:发生错误的脚本 URL(字符串)
  • lineno:发生错误的行号(数字)
  • colno:发生错误的列号(数字)
  • error:Error 对象(对象)

若该函数返回 true,则阻止执行默认事件处理函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 常规运行时错误,可以捕获 ✅
window.onerror = function(message, source, lineno, colno, error) {
  console.log('捕获到异常:',{message, source, lineno, colno, error});
}
console.log(notdefined);

// 语法错误,不能捕获 ❌
window.onerror = function(message, source, lineno, colno, error) {
  console.log('捕获到异常:',{message, source, lineno, colno, error});
}
const notdefined,

// 异步错误,可以捕获 ✅
window.onerror = function(message, source, lineno, colno, error) {
  console.log('捕获到异常:',{message, source, lineno, colno, error});
}
setTimeout(() => {
  console.log(notdefined);
}, 0)

// 资源错误,不能捕获 ❌
<script>
  window.onerror = function(message, source, lineno, colno, error) {
  console.log('捕获到异常:',{message, source, lineno, colno, error});
  return true;
}
</script>
<img src="https://unknown/image/null.png">

window.addEventListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 图片、script、css加载错误,都能被捕获 ✅
<script>
  window.addEventListener(
    "error",
    (error) => {
      console.log("捕获到异常:", error)
    },
    true
  )
</script>
<img src="https://unknown/image/null.png" />
<script src="https://unknown/foundnull.js"></script>
<link href="https://unknown/foundnull.css" rel="stylesheet" />

// new Image错误,不能捕获 ❌
<script>
  window.addEventListener(
    "error",
    (error) => {
      console.log("捕获到异常:", error)
    },
    true
  )
</script>
<script>
  new Image().src = "https://unknown/image/null.png"
</script>

// fetch错误,不能捕获 ❌
<script>
  window.addEventListener(
    "error",
    (error) => {
      console.log("捕获到异常:", error)
    },
    true
  )
</script>
<script>
  fetch("https://unknown/test")
</script>

异步错误

如果使用 try/catch 能捕获 await 的错误 普通 Promise 错误 使用 catch

全局捕获错误 - unhandledrejection

1
2
3
4
5
// 全局统一处理Promise
window.addEventListener("unhandledrejection", function (e) {
  console.log("捕获到异常:", e)
})
fetch("https://unknown/test")

Vue 的错误

vue 的错误会被 vue 自动捕获,并且抛给 Vue.config.errorHandler。

1
2
3
4
5
6
7
8
/**
 * 全局捕获Vue错误,直接扔出给onerror处理
 */
Vue.config.errorHandler = function (err) {
  setTimeout(() => {
    throw err
  })
}

React 错误

react 通过 componentDidCatch,声明一个错误边界的组件

数据上报接口

使用 1*1 像素的 gif 图片进行上报,有以下几点好处

  • 不会阻塞页面渲染
  • 图片天然跨域
  • 不会携带 Cookie
  • 不需等待服务器返回数据
  • gif 图片所需流量最小

但数据太大,最好还是用 post

本文由作者按照 CC BY 4.0 进行授权