需要处理哪些异常?
JS 语法错误、代码异常
AJAX 请求异常
静态资源加载异常
Promise 异常
Iframe 异常
跨域 Script error
崩溃和卡顿
一、try…catch…
同步代码可以捕获到异常,语法错误和异步代码无法捕捉异常。
同步错误
try {
let name = 'jartto';
console.log(nam);
} catch(e) {
console.log('捕获到异常:',e);
}
捕获到异常: ReferenceError: nam is not defined
at <anonymous>:3:15
语法错误
try {
let name = 'jartto;
console.log(nam);
} catch(e) {
console.log('捕获到异常:',e);
}
Uncaught SyntaxError: Invalid or unexpected token
异步错误
try {
setTimeout(() => {
undefined.map(v => v);
}, 1000)
} catch(e) {
console.log('捕获到异常:',e);
}
Uncaught TypeError: Cannot read property 'map' of undefined
at setTimeout (<anonymous>:3:11)
二、 window.onerror
当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()
同步代码、异步代码可以捕获;语法错误、网络请求(包括静态资源请求,接口请求)都无法捕获
同步错误
window.onerror = function(message, source, lineno, colno, error) {
// message:错误信息(字符串)。
// source:发生错误的脚本URL(字符串)
// lineno:发生错误的行号(数字)
// colno:发生错误的列号(数字)
// error:Error对象(对象)
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
Jartto;
异步错误
window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
setTimeout(() => {
Jartto;
});
捕获到异常: {message: "Uncaught ReferenceError: Jartto is not defined", source: "http://127.0.0.1:8001/", lineno: 36, colno: 5, error: ReferenceError: Jartto is not defined
at setTimeout (http://127.0.0.1:8001/:36:5)}
语法错误
window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
let name = 'Jartto
Uncaught SyntaxError: Invalid or unexpected token
网络请求
<script>
window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
return true;
}
</script>
<img src="./jartto.png">
Uncaught ReferenceError: Jartto is not defined
at setTimeout ((index):36)
三、window.addEventListener
当一项资源(如图片或脚本)加载失败
<scritp>
window.addEventListener('error', (error) => {
console.log('捕获到异常:', error);
}, true)
</script>
<img src="./jartto.png">
四、promise.catch
在 promise 中使用 catch 可以非常方便的捕获到异步 error ,这个很简单。
没有写 catch 的 Promise 中抛出的错误无法被 onerror 或 try…catch… 捕获到,所以我们务必要在 Promise 中不要忘记写 catch 处理抛出的异常。
解决方案: 为了防止有漏掉的 Promise 异常,建议在全局增加一个对 unhandledrejection 的监听,用来全局监听Uncaught Promise Error。使用方式:
window.addEventListener("unhandledrejection", function(e){
console.log(e);
});
window.addEventListener("unhandledrejection", function(e){
e.preventDefault()
console.log('捕获到异常:', e);
return true;
});
Promise.reject('promise error');
e.preventDefault()的作用是阻止事件的默认行为,在这里可以阻止错误直接出现在控制台
五、VUE errorHandler
Vue.config.errorHandler = (err, vm, info) => {
console.error('通过vue errorHandler捕获的错误');
console.error(err);
console.error(vm);
console.error(info);
}
六、React 异常捕获
React 16 提供了一个内置函数 componentDidCatch,使用它可以非常简单的获取到 react 下的错误信息
componentDidCatch(error, info) {
console.log(error, info);
}
七、iframe 异常
对于 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});
return true;
};
</script>
八、Script error
一般情况,如果出现 Script error 这样的错误,基本上可以确定是出现了跨域问题:
我们为 script 标签添加 crossOrigin 属性,这样就可以捕捉到(trycatch等)
<script src="http://jartto.wang/main.js" crossorigin></script>
九、崩溃和卡顿
- 利用 window 对象的 load 和 beforeunload 事件实现了网页崩溃的监控。
- 我们可以使用 Service Worker 来实现网页崩溃的监控。
十、 错误上报
-
通过 Ajax 发送数据
因为 Ajax 请求本身也有可能会发生异常,而且有可能会引发跨域问题,一般情况下更推荐使用动态创建 img 标签的形式进行上报。
-
动态创建 img 标签的形式
function report(error) {
let reportUrl = 'http://jartto.wang/report';
new Image().src = `${reportUrl}?logs=${error}`;
}
总结
- 可疑区域增加 Try-Catch
- 全局监控 JS 异常 window.onerror
- 全局监控静态资源异常 window.addEventListener
- 捕获没有 Catch 的 Promise 异常:unhandledrejection
- VUE errorHandler 和 React componentDidCatch
- 监控网页崩溃:window 对象的 load 和 beforeunload
- 跨域 crossOrigin 解决