前端错误监控

常见错误类型

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

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

// 常规运行时错误,可以捕获 ✅
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 捕获。
window.onerror = function(message, source, lineno, colno, error) { ... }

函数参数:

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

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

// 常规运行时错误,可以捕获 ✅
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

// 图片、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

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

Vue 的错误

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

/**
* 全局捕获Vue错误,直接扔出给onerror处理
*/
Vue.config.errorHandler = function (err) {
setTimeout(() => {
throw err
})
}

React 错误

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

数据上报接口

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

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

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