前端错误监控

监控JavaScript错误处理

常见错误类型

| 错误 | 解释 | 示例 | | -------------- | -------------------------- | ------------------------------------ | | 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} 23

window.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"> 29

window.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