全局捕获-架构侧
-
js全局异常捕获:window.onEerror 和 window.addEventLisenter('error')
-
Promise全局异常捕获:unhandledrejection
-
框架级的全局异常捕获
- React:
React
的ErrorBoundary
scala// ErrorBoundary的示例 class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { this.setState({ hasError: true }); // 在这里可以做异常的上报 logErrorToMyService(error, info); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } <ErrorBoundary> <MyWidget /> </ErrorBoundary>
- Vue:
Vue
的Vue.config.errorHandler
- axios: 请求统一底层封装异常处理拦截器
interceptors
- React:
全局捕获-框架层
Vue 用 errorHandler
和React 用 componentDidCatch
局部捕获-业务侧
可疑代码块try-catch
try catch能捕获捉到运行时非异步错误,无法捕获语法错误和异步错误。这个需要注意。
合理使用,不要过度使用。有得异常需要抛出去给外部处理。
常见的需要注意用try-catch包裹,捕获异常的情况
- JSON处理必须使用try catch捕获异常
javascript
try {
const res=fetch(*)
JSON.parse(res); // res 为服务端返回的数据
} catch(e) {
// 捕获到详细的错误,在这里处理日志上报或其他异常处理等逻辑,如是否提示用户,是否有异常下的兜底数据,比如使用缓存数据等
console.error("服务端数据格式返回异常,无法解析", res);
}
// 注意:下面的异常try catch无法捕获
try {
setTimeout(() => {
undefined.map(v => v);
}, 1000)
} catch(e) {
console.log("捕获到异常:", e);
}
- async await异步请求
- 正则表达式处理
- buffer处理
Promise异常:
注意未被捕获的promise异常会作为全局异常抛出。
- 局部Promise捕获两种方式:
javascript
// 1. Promise().catch()
let promise = new Promise((resolve,reject)=>{}).catch(e=>{
// handle error
})
// 2. async/await + try/catch
let promise = new Promise();
async function test() {
try {
await promise;
} catch (e) {
// handle error
}
}
- 用Promise().catch(),
- 全局Promise异常用window.addEventListener("unhandledrejection")
注意:
- Promise自己的异常只能被自己catch, 或在try/catch里以await的方式调用来捕获。否则就会作为ERR_UNHANDLED_REJECTION异常抛出到全局。
- 外层Promise不能不能捕获内层Promise的异常。
javascript
let p1 = new Promise(async (resolve, reject) => {
return reject(100); // 被捕获
});
async function fn() {
try {
let result = await p1;
console.log(2, result); //这里不会执行
} catch (e) {
console.log("e:", e); //这里不会执行
}
}
fn();
javascript
let p1 = new Promise(async (resolve, reject) => {
return reject(100); // 未被捕获,会抛出全局异常:ERR_UNHANDLED_REJECTION
});
function fn() {
try {
let result = p1;
console.log(2, result); //这里不会执行
} catch (e) {
console.log("e:", e); //这里不会执行
}
}
fn();
javascript
let p1 = new Promise(async (resolve, reject) => {
console.log("after reject");
return Promise.reject(100); // 未被捕获,会抛出全局异常:ERR_UNHANDLED_REJECTION
});
async function fn() {
try {
let result = await p1;
console.log(2, result); //这里不会执行
} catch (e) {
console.log("e:", e); //这里不会执行
}
}
fn();
javascript
let p1 = new Promise(async (resolve, reject) => {
return Promise.reject(100); // 未被捕获,会抛出全局异常:ERR_UNHANDLED_REJECTION
}).catch((e) => {
console.log("promise out e", e); // 这里不会执行
});
async function fn() {
try {
let result = await p1;
console.log(2, result); //这里不会执行
} catch (e) {
console.log("e:", e); //这里不会执行
}
}
fn();
- Promise里同步抛出的异常,会触发Promise.reject而被捕获。但异步抛出的异常,不会触发Promise.reject,因此不会被捕获。
javascript
new Promise((resolve, reject) => {
throw new Error("Error1"); // 等效于reject
}).catch((e) => {
console.log("异常被捕获到了1");
});
new Promise(async (resolve, reject) => {
reject(new Error("Error2"));
}).catch((e) => {
console.log("异常被捕获到了2");
});
new Promise(async () => {
throw new Error("Error3");
}).catch((e) => {
console.log("异常被捕获到了3");
});
接口请求异常:
- Fetch 用async await + try catch
- Axios 请求,自行处理自定义的异常上报
全局静态资源异常监控:
window.addEventListener("error") 或者资源标签的onError属性