背景
在前端项目中,当访问空对象的属性、或者空函数调用时,会导致渲染异常,出现白屏的情况,直接导致产品不可用,严重影响了用户体验。白屏错误出现的概率小,但是严重级别高,因此需要对白屏错误做一个拦截,引导用户在白屏情况下可以做什么,如:联系负责人、刷新页面等。
目标
- 拦截白屏错误,当页面出现白屏时,渲染备用UI,引导用户联系负责人或者刷新页面。
- 对错误信息进行上报。
错误拦截方案调研
方案一 React错误边界
使用React错误边界处理错误,利用统一的高阶组件包裹业务组件。
import React, { ErrorInfo } from 'react';
interface IState {
hasError: boolean;
error: Error | null;
errorInfo: ErrorInfo | null;
}
export function withErrorHandler(Component, ErrorComp?) {
class WithErrorHandler extends React.Component<any, IState> {
constructor(props) {
super(props);
this.state = {
hasError: false,
// 错误信息,是否需要展示出来呢?
error: null,
errorInfo: null,
};
}
public componentDidCatch(error, info) {
this.setState({ hasError: true, error, errorInfo: info });
// 监控上报错误
}
public render() {
if (this.state.hasError) {
return (ErrorComp || <div style={{padding: '20px'}}>出现了严重错误,无法渲染</div>);
}
return <Component {...this.props} />;
}
}
WithErrorHandler.displayName = `withErrorHandler(${Component.displayName})`;
return WithErrorHandler;
}
方案二 使用插件
使用插件react-transform-catch-errors。
安装 babel-plugin-react-transform 和 react-transform-catch-errors
配置.babelrc参考如下:
{
"presets": ["es2015", "stage-0"],
"env": {
// only enable it when process.env.NODE_ENV is 'development' or undefined
"development": {
"plugins": [["react-transform", {
"transforms": [{
"transform": "react-transform-catch-errors",
// now go the imports!
"imports": [
// the first import is your React distribution
// (if you use React Native, pass "react-native" instead)
"react",
// the second import is the React component to render error
// (it can be a local path too, like "./src/ErrorReporter")
"./src/ErrorReporter"
// the third import is OPTIONAL!
// when specified, its export is used as options to the reporter.
// see specific reporter's docs for the options it needs.
// it will be imported from different files so it either has to be a Node module
// or a file that you configure with Webpack/Browserify/SystemJS to resolve correctly.
// for example, see https://github.com/gaearon/babel-plugin-react-transform/pull/28#issuecomment-144536185
// , "my-reporter-options"
]
}]
// note: you can put more transforms into array
// this is just one of them!
}]]
}
}
}
方案三 自定义React.createElement
写一个错误组件,重写React.createElement。使用 babel-plugin-transform-react-jsx 来更改 jsx 转化逻辑,将 jsx 用到的 createElement 替换成自己写的createElement方法。
错误监控上报
上报方案
使用的是内部工具上报。大概流程是:将Error对象进行上报,然后再接入Source Map,这样即可查看错误并定位到代码。
上报内容
- 所在页面url
- path
- 路由参数
- 当前用户
- 时间
- 错误类型
- 错误描述
- 堆栈信息
数据分析
我们将数据生成报表,观察到报错信息里,发生ChunkLoadError的错误居多。分析后,发现存在如下几种错误原因:
- 浏览器无法找到文件或者文件已经过时。可能是因为项目上线了一次,但是用户停留在旧页面,访问的时候,旧文件已经不存在了。
- 网络原因。可能是网络突然断掉。
总结
- 接触到一个陌生的技术需求,首先应该明确需求的背景和意义、要解决的问题。再去网上调研看是否有成熟的解决方案,多调研几种方案,对比优劣,找到最合适的方案。
- 白屏错误,即渲染异常,这种错误出现的可能性小,但严重级别很高。
参考资料:
1.前端异常处理最佳实践
2.Top 10 JavaScript errors from 1000+ projects (and how to avoid them)