前端所有错误类型以及捕获方式
JS Error
1. window.addEventListener('error',function(err){
console.log('事件捕获...',err)
},true)
2. window.onerror=function(err){
console.log('事件捕获...',err)
}
报错信息:Script error .
当加载自不同域的脚本中发生语法错误时,浏览器为避免信息泄露的安全风险,语法错误的细节将不会报告给浏览器console中,而是使用"Script error."信息代替。
一般而言,如果是第三方的JS资源,和页面自身的URL产生了跨域问题,所以引起了"Script Error"。
解决方法:我们为 script 标签添加 crossOrigin 属性。
<script src='xxx.com' crossOrigin />
定时器内部函数抛出错误
定时器内部函数的错误会抛到顶层,无法被try...catch
try {
setTimeout(() => {
null.map(v => v); }, 1000)
}
catch(e) {
console.log('捕获到异常:',e);
}
1. window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
2. window.addEventListener('error',function(err){
console.log('捕获到异常...',err)
},true)
静态资源加载的异常
当一项资源(如图片和脚本加载失败),加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror处理函数。这些error事件不会向上冒泡到window, 不过(至少在 Chrome 中)能被全局的addEventListener 捕获。
window.onerror不能捕捉静态资源加载的异常,addEventListener可以捕捉到。
window.addEventListener('error', (error) => {
console.log('捕获到异常:', error);
}, true)
iframe内部异常
可通过window.onerror捕获
<iframe src="./iframe.html" frameborder="0"></iframe>
<script>
window.frames[0].onerror = function (message, source, lineno, colno, error) {
console.log('捕获到 iframe 异常:', {message, source, lineno, colno, error});
};
</script>
网络请求的异常
由于网络请求异常不会事件冒泡,就算在捕获中无法判断 HTTP 的状态是 404 或是比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。
所以我们一般配合一些请求库去完成完成网络请求异常的捕获。比如axios进行回调捕获,或者ajax回调捕获,或是promise化catch。
Promise Catch
unhandledrejection 只能捕获未显式处理的Promise异常
// 能触发 unhandledrejection ,因为未显式处理reason
Promise.reject('error').then()
Promise.reject('error').then(console.log)
// 不能触发 unhandledrejection ,因为已处理reason
Promise.reject('error').then(console.log, console.log)
// 不能触发 unhandledrejection ,因为没处理reason,直接抛出异常
Promise.reject('error')
监听捕获方法
// 全局监听 Uncaught Promise Error。
window.addEventListener("unhandledrejection", function(e){
// e.preventDefault(); // 阻止异常向上抛出
console.log('捕获到异常:', e);
});
window.onunhandledrejection = function(e){
// e.preventDefault(); // 阻止异常向上抛出到全局,不在console中显示
console.log('捕获到异常:', e);
};
常见框架处理
React错误处理
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
Vue错误处理
Vue.config.errorHandler = function (err, vm, info) {
// vm为抛出异常的 Vue 实例
// info为 Vue 特定的错误信息,比如错误所在的生命周期钩子
let {
message, // 异常信息
name, // 异常名称
script, // 异常脚本url
line, // 异常行号
column, // 异常列号
stack // 异常堆栈信息
} = err;
})
数据上报方式(可用于数据埋点)
关闭或者最小化浏览器时回调
- beforeunload (关闭前确认弹窗) 部分移动端不触发
- unload 关闭时 部分移动端不触发
- pagehide 隐藏时 部分移动端不触发
延迟浏览器关闭或跳转的方法:
用户场景:当用户导航到另一个页面或者关闭页面,希望关闭或跳转前将数据完整发送。
- 创建一个img元素并设置它的src。阻塞主线程,大多数浏览器会延迟卸载以加载图像。
- 在src中创建埋点url,服务端通过get方式接收
- 原理:占用浏览器主线程,大多数浏览器会延迟卸载以加载图像。
- 创建几秒钟的无操作循环。
let currTime=new Date().valueOf())
while(new Date()>currTime+3000){}
- 通过配置将XHR同步发送请求
- axios默认是异步的,浏览器可能会过早关闭或跳转导致取消发送
- 通过配置将XHR改为同步发送请求,但是可能会影响用户跳转的速度。
- sendBeaconAPI 64KB限制 IE兼容性问题 post请求
- body大小64KB限制 IE兼容性问题 post请求
- 浏览器将 Beacon 请求排队让它在空闲的时候执行
- 浏览器进行了优化:可以将 Beacon 请求合并到其他请求上,一同处理, 尤其在移动环境下。
- 异步发送 不阻塞进程