一、错误异常类型
try-catch
- 基础语法:
try{
console.log(window.a.b)
}catch{
console.log(e)
}
- 存在问题
- 只能捕获同步错误,捕获不了异步错误,如下是捕获不了的
try{
setTimeout(()=>{
console.log(window.a.b)
},2000)
}catch{
console.log(e)
}
// Uncaught TypeError: Cannot read property 'b' of undefined
- 捕获不了语法错误
try{
let name = 'hello world;
console.log(name)
}catch{
console.log(e)
}
// SyntaxError: Unterminated string constant
window.onError获取
- window.onError是全局捕获方式,可以捕获同步和异步错误,捕获到的信息也比较丰富,可以得到具体的异常信息、异常文件的URL、异常的行号与列号及异常的堆栈信息。一般写在代码的最前边
throw new Error('啦啦啦=====')
window.onerror = function(message, source, lineno, colno, error) {
函数参数:
* message:错误信息(字符串)。可用于HTML onerror=""处理程序中的event。
* source:发生错误的脚本URL(字符串)
* lineno:发生错误的行号(数字)
* colno:发生错误的列号(数字)
* error:Error对象
* 若该函数返回true,则阻止执行默认事件处理函数,如异常信息不会在console中打印。没有返回值或者返回值为false的时候,异常信息会在console中打印
console.log('message',message)
console.log('source', source)
console.log('lineno',lineno)
console.log('colno',colno)
console.log('error', error)
}
// message Uncaught Error: 啦啦啦=====
// source http://localhost:3000/static/js/vendors~main.chunk.js
// lineno 25431
// colno 9
// error Error: 啦啦啦=====
at App (App.js:5)
at renderWithHooks (react-dom.development.js:14985)
at mountIndeterminateComponent (react-dom.development.js:17811)
at beginWork (react-dom.development.js:19049)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
at invokeGuardedCallback (react-dom.development.js:4056)
...
- 缺点有两个,一是捕获不到网络异常错误,比如静态资源加载错误,二是跨域脚本无法捕获到正确的异常信息,这种情况会统一返回一个Script error,可以通过在script标签上使用crossorigin属性来规避这个问题
addEventListener('error')
- 监听js运行时错误事件,与onerror的功能大体类似,但是没有onerror打印信息丰富,但可以捕获网络资源加载错误
- window.addEventListener的第三个参数:useCapture,默认值为false(即 使用事件冒泡),为true则是事件捕获
- 【注意!】如果与window.onerror一起使用要注意去重,因为都可以捕获js错误
window.addEventListener('error', function(event) { ... })
当资源(如img或script)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会向上冒泡到window,但可以在捕获阶段被捕获
因此如果要全局监听资源加载错误,需要在捕获阶段捕获事件
//图片加载失败使用默认图片,依旧加载失败超过三次使用base64图片
window.addEventListener('error',function(e){
let target = e.target, // 当前dom节点
tagName = target.tagName,
count = Number(target.dataset.count ) || 0, // 以失败的次数,默认为0
max= 3; // 总失败次数,此时设定为3
// 当前异常是由图片加载异常引起的
if( tagName.toUpperCase() === 'IMG' ){
if(count >= max){
target.src = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//AK3/ALYH+5hX6FV5N4Y/5GHwx/vyf+iJa9ZrysPhoYVShDZu/potDmwWFhhIzhT2bv6aLQ//Z';
}else{
target.dataset.count = count + 1;
target.src = '//xxx/default.jpg';
}
}
},true)
window.addEventListener('unhandledrejection')
捕获异步错误的方式。没有catch的promise错误,没有办法被window.onerror和try-catch捕获到,这时候就需要unhandledrejection
//捕获到的错误信息在err.reason上
new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('not found')
})
})
window.addEventListener('unhandledrejection',function (err: any) {
console.log(err.reason)
})
// Uncaught (in promise) not found
iFrame 异常
<iframe src="./iframe.html"></iframe>
<script>
window.frames[0].onerror=function(message, source, lineno, colno, error) {
console.log('捕获到的iframe异常',message, source, lineno, colno, error)
}
</script>
捕获到的iframe异常 Uncaught TypeError: Cannot read property 'b' of undefined http://localhost:3000/iframe.html 11 40 TypeError: Cannot read property 'b' of undefined
崩溃和卡顿
网页响应慢和奔溃的情况,卡顿即js没有办法及时执行代码,奔溃,即js不执行了。可以利用window的load和beforeLoad,以及serviceWorker开启一个线程进行监控
第三方库的异常捕获能力
- vue的话.vue文件里的错误onerror是捕获不到的,这时候要在全局的Vue.config.errorHandler 中捕获错误
Vue.config.errorHandler = function (err, vm, info) {
console.log(err)
}
- react的ErrorBoundary 错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。
接口请求的错误信息
接口请求的错误信息,接口错误信息的捕获一般会在axios的拦截器里边写,当接口code!==0,或者是catch捕获到错误时上报。
- 这里着重说一下catch中捕获到的错误,有时候会出现JSON.stringify之后的错误信息是空对象的情况。这是因为error的具体错误信息有时候是不可枚举的,这时候就用上了JSON.stringfy的第二个参数
console.log(JSON.stringify(error,Object.getOwnPropertyNames(error)))
二、生产环境下的错误异常处理问题
sourcemap
1.生产环境下的所有报的错误信息都显示在第一行了,这是因为在生产环境下被压缩了,而保留sourcemap就可以利用webpack打包后生成的.map文件来追踪具体的错误位置。但这种做法会把源代码暴露给用户,推荐的方式是在服务端对接收到的错误信息使用source-map解析。
2.webpack自定义插件实现sourcemap自动上传