是指用户在使用应用时,没法获得预期的结果。不一样的异常带来的后果程度不一样,轻则引发用户使用不悦,重则致使产品没法使用,从而使用户丧失对产品的承认。css
异常 | 频率 |
---|---|
JavaScript异常(语法错误、代码错误) | 常常 |
静态资源加载异常(img、js、css) | 偶尔 |
Ajax 请求异常 | 偶尔 |
promise异常 | 较少 |
iframe 异常 | 较少 |
try-catch 只能捕获同步运行错误,对语法和异步错误却捕获不到。html
一、同步运行错误前端
try {
kill;
} catch(err) {
console.error('try: ', err);
}
复制代码
结果:try: ReferenceError: kill is not defined
vue
二、没法捕获语法错误react
try {
let name = '1; } catch(err) { console.error('try: ', err); } 复制代码
结果:Unterminated string constant
git
编译器可以阻止运行语法错误。github
三、没法捕获异步错误promise
try {
setTimeout(() => {
undefined.map(v => v);
}, 1000);
} catch(err) {
console.error('try: ', err);
}
复制代码
结果:Uncaught TypeError: Cannot read property 'map' of undefined
浏览器
当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()。若该函数返回true,则阻止执行默认事件处理函数。bash
一、同步运行错误
/**
* @param {String} message 错误信息
* @param {String} source 出错文件
* @param {Number} lineno 行号
* @param {Number} colno 列号
* @param {Object} error error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
console.error('捕获异常:', message, source, lineno, colno, error);
return true;
};
kill;
复制代码
结果:捕获异常: Uncaught ReferenceError: kill is not defined
二、没法捕获语法错误
/**
* @param {String} message 错误信息
* @param {String} source 出错文件
* @param {Number} lineno 行号
* @param {Number} colno 列号
* @param {Object} error error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
console.error('捕获异常:', message, source, lineno, colno, error);
return true;
};
let name = '1; 复制代码
结果:Unterminated string constant
编译器可以阻止运行语法错误。
三、异步错误
/**
* @param {String} message 错误信息
* @param {String} source 出错文件
* @param {Number} lineno 行号
* @param {Number} colno 列号
* @param {Object} error error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
console.error('捕获异常:', message, source, lineno, colno, error);
return true;
};
setTimeout(() => {
undefined.map(v => v);
}, 1000);
复制代码
结果:捕获异常: Uncaught TypeError: Cannot read property 'map' of undefined
当一项资源(如<img>
或<script>
)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener捕获。
<script>
window.addEventListener('error', (err) => {
console.error('捕获异常:', err);
}, true);
</script>
<img src="./test.jpg" />
复制代码
结果:捕获异常:Event {isTrusted: true, type: "error", target: img, currentTarget: Window, eventPhase: 1, …}
当Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件;这可能发生在 window 下,但也可能发生在 Worker 中。 这对于调试回退错误处理很是有用。
window.addEventListener("unhandledrejection", (err) => {
err.preventDefault();
console.error('捕获异常:', err);
});
Promise.reject('promise');
复制代码
结果:捕获异常:PromiseRejectionEvent {isTrusted: true, promise: Promise, reason: "promise", type: "unhandledrejection", target: Window, …}
Vue.config.errorHandler = (err, vm, info) => {
console.error('捕获异常:', err, vm, info);
}
复制代码
React 16,提供了一个内置函数componentDidCatch
,使用它能够很是简单的获取到React
下的错误信息。
componentDidCatch(error, info) {
console.error('捕获异常:', error, info);
}
复制代码
可是,推荐ErrorBoundary
用户界面中的JavaScript错误不该破坏整个应用程序。为了为React用户解决此问题,React 16引入了“错误边界”的新概念。
新建ErrorBoundary.jsx
组件:
import React from 'react';
import { Result, Button } from 'antd';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, info: '' };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
this.setState({
info: error + ''
});
}
render() {
if (this.state.hasError) {
// 你能够渲染任何自定义的降级 UI
return (
<Result
status="500"
title="500"
subTitle={this.state.info}
extra={<Button type="primary">Report feedback</Button>}
/>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
复制代码
使用:
<ErrorBoundary>
<App />
</ErrorBoundary>
复制代码
注意
错误边界不会捕获如下方面的错误:
因为浏览器设置的“同源策略”,没法很是优雅的处理iframe异常,除了基本属性(例如其宽度和高度)以外,没法从iFrame得到不少信息。
<script>
document.getElementById("myiframe").onload = () => {
const self = document.getElementById('myiframe');
try {
(self.contentWindow || self.contentDocument).location.href;
} catch(err) {
console.log('捕获异常:' + err);
}
};
</script>
<iframe id="myiframe" src="https://nibuzhidao.com" frameBorder="0" />
复制代码
业界很是优秀的一款监控异常的产品,做者也是用的这款,文档齐全。
一、Ajax发送数据
二、动态建立img标签
若是异常数据量大,致使服务器负载高,调整发送频率(能够考虑把异常信息存储在客户端,设定时间阀值,进行上报)或设置采集率(采集率应该经过实际状况来设定,随机数,或者某些用户特征都是不错的选择)。