1.try/catch
只能捕获代码常规的运行错误,语法错误和异步错误不能捕获到
// 示例1:常规运行时错误,可以捕获 ✅
try {
let a = undefined;
if (a.length) {
console.log('111');
}
} catch (e) {
console.log('捕获到异常:', e);
}
// 示例2:语法错误,不能捕获 ❌
try {
const notdefined,
} catch(e) {
console.log('捕获不到异常:', 'Uncaught SyntaxError');
}
// 示例3:异步错误,不能捕获 ❌
try {
setTimeout(() => {
console.log(notdefined);
}, 0)
} catch(e) {
console.log('捕获不到异常:', 'Uncaught ReferenceError');
}
2.window.onerror
window.onerror 可以捕获常规错误、异步错误,但不能捕获资源错误
window.onerror = function(message, source, lineno, colno, error) {
console.log("捕获到的错误信息是:", message, source, lineno, colno, error);
};
// 示例1:常规运行时错误,可以捕获 ✅
console.log(notdefined);
// 示例2:语法错误,不能捕获 ❌
const notdefined;
// 示例3:异步错误,可以捕获 ✅
setTimeout(() => {
console.log(notdefined);
}, 0);
// 示例4:资源错误,不能捕获 ❌
let script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://www.test.com/index.js";
document.body.appendChild(script);
3.Promise错误
Promise中抛出的错误,无法被 window.onerror、try/catch、 error 事件捕获到,可通过 unhandledrejection 事件来处理
try {
new Promise((resolve, reject) => {
JSON.parse("");
resolve();
});
} catch (err) {
// try/catch 不能捕获Promise中错误 ❌
console.error("in try catch", err);
}
// error事件 不能捕获Promise中错误 ❌
window.addEventListener(
"error",
error => {
console.log("捕获到异常:", error);
},
true
);
// window.onerror 不能捕获Promise中错误 ❌
window.onerror = function(message, source, lineno, colno, error) {
console.log("捕获到异常:", { message, source, lineno, colno, error });
};
// unhandledrejection 可以捕获Promise中的错误 ✅
window.addEventListener("unhandledrejection", function(e) {
console.log("捕获到异常", e);
// preventDefault阻止传播,不会在控制台打印
e.preventDefault();
});
4.window.addEventListener
当静态资源加载失败时,会触发 error 事件, 此时 window.onerror 不能捕获到
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<script>
window.addEventListener('error', (error) => {
console.log('捕获到异常:', error);
}, true)
</script>
<!-- 图片、script、css加载错误,都能被捕获 ✅ -->
<img src="https://test.cn/×××.png">
<script src="https://test.cn/×××.js"></script>
<link href="https://test.cn/×××.css" rel="stylesheet" />
<script>
// new Image错误,不能捕获 ❌
// new Image运用的比较少,可以自己单独处理
new Image().src = 'https://test.cn/×××.png'
</script>
</html>
5.Vue错误
Vue项目中,window.onerror 和 error 事件不能捕获到常规的代码错误
//异常代码:
export default {
created() {
let a = null;
if(a.length > 1) {
// ...
}
}
};
//main.js 添加捕获代码:
window.addEventListener('error', (error) => {
console.log('error', error);
});
window.onerror = function (msg, url, line, col, error) {
console.log('onerror', msg, url, line, col, error);
};
//控制台会报错,但是 window.onerror 和 error 不能捕获到
//vue 通过 `Vue.config.errorHander` 来捕获异常:
Vue.config.errorHandler = (err, vm, info) => { console.log('进来啦~', err); }
6.React 错误
从 react16 开始,官方提供了 ErrorBoundary 错误边界的功能,被该组件包裹的子组件,render 函数报错时会触发离当前组件最近父组件的ErrorBoundary 生产环境,一旦被 ErrorBoundary 捕获的错误,也不会触发全局的 window.onerror 和 error 事件
// 父组件代码
import React from 'react';
import Child from './Child.js';
// window.onerror 不能捕获render函数的错误 ❌
window.onerror = function (err, msg, c, l) {
console.log('err', err, msg);
};
// error 不能render函数的错误 ❌
window.addEventListener( 'error', (error) => {
console.log('捕获到异常:', error);
},true
);
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// componentDidCatch 可以捕获render函数的错误
console.log(error, errorInfo)
// 同样可以将错误日志上报给服务器
reportError(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
function Parent() {
return (
<div>
父组件
<ErrorBoundary>
<Child />
</ErrorBoundary>
</div>
);
}
export default Parent;
// 子组件代码
// 子组件 渲染出错
function Child() {
let list = {};
return (
<div>
子组件
{list.map((item, key) => (
<span key={key}>{item}</span>
))}
</div>
);
}
export default Child;
// 同vue项目的处理类似,react项目中,可以在 componentDidCatch 中将捕获的错误上报
componentDidCatch(error, errorInfo) {
// handleError方法用来处理错误并上报
handleError(err);
}
7.跨域问题
如果当前页面中,引入了其他域名的JS资源,如果资源出现错误,error 事件只会监测到一个 script error
的异常。
是由于浏览器基于安全考虑
,故意隐藏了其它域JS文件抛出的具体错误信息,这样可以有效避免敏感信息无意中被第三方(不受控制的)脚本捕获到,因此,浏览器只允许同域下的脚本捕获具体的错误信息
window.addEventListener("error", error => {
console.log("捕获到异常:", error);
}, true );
// 当前页面加载其他域的资源,如https://www.test.com/index.js
<script src="https://www.test.com/index.js"></script>
// 加载的https://www.test.com/index.js的代码
function fn() {
JSON.parse("");
}
fn();
// 解决方法:
// 前端script加crossorigin,后端配置 Access-Control-Allow-Origin 添加 crossorigin 后可以捕获到完整的报错信息:
<script src="https://www.test.com/index.js" crossorigin></script>