js代码运行时,希望能捕获异常错误,上报后台监控,及时修复bug,那么如何捕获错误?下面我们来看下有哪些错误。
语法错误
同步错误
window.addEventListener('error', ()=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
throw new Error();
// "addEventListener"
异步错误
window.addEventListener('error', ()=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
setTimeout(()=>{
throw new Error();
}, 10)
// "addEventListener"
资源错误(img、script、object等)
// 资源加载前,必须先监听错误事件
window.addEventListener('error', ()=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
<img src="../404.png" />
<script src="../404.png"></script>
// "addEventListener"
// "addEventListener"
console.error错误
var consoleError = window.console.error;
window.console.error = function () {
console.log('console')
consoleError && consoleError.apply(window, arguments);
};
console.error('error')
// "console"
// "error"
js跨域错误
// 跨域错误默认提示 Script error
window.addEventListener('error', ()=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
// 客户端添加crossorigin属性
// 服务端添加Access-Control-Allow-Origin: *
// 否则只提示Script error,无法获取具体错误信息
<script src="https://dss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/jquery/jquery-1.10.2.min_65682a2.js"></script>
// "addEventListener"
promise错误
window.addEventListener('error', ()=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
new Promise((resolve, reject)=>{
throw new Error();
})
new Promise((resolve, reject)=>{
resolve('')
})
.then((data)=>{
throw new Error();
})
new Promise((resolve, reject)=>{
throw new Error();
})
.catch((err)=>{
console.error(err)
})
// [object Error] { ... }
// "unhandledrejection"
// "unhandledrejection"
async/await错误
window.addEventListener('error', (e)=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
async function compute () {
let a = 1;
let b = await a + 2;
throw new Error('async error')
}
compute()
// "unhandledrejection"
genrator错误
window.addEventListener('error', (e)=>{
console.log('addEventListener')
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
// gennerator
function* F() {
throw new Error("gennerator-throw在函数体外抛出的错误")
yield 1;
return "gennerator-value";
}
var f = F();
f.next();
// "addEventListener"
iframe错误
var frames = window.frames;
for (var i = 0; i < frames.length; i++) {
frames[i].addEventListener('error', (e)=>{
console.log('addEventListener')
console.log(e)
}, true);
frames[i].addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
}, true);
}
请求错误(XMLHttpRequest、fetch)
window.addEventListener('error', (e)=>{
console.log('addEventListener')
console.log(e)
}, true);
window.addEventListener("unhandledrejection", function(e) {
console.log('unhandledrejection')
console.log(e)
}, true);
// 请求返回错误
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
// 无效请求
fetch('http://example.com/404.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
const xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=state_Change;
xmlhttp.open("GET", 'http://127.0.0.1:8000/',true);
xmlhttp.send(null);
function state_Change(){
if (xmlhttp.readyState == 4){// 4 = "loaded"
if (xmlhttp.status == 200){// 200 = "OK"
throw new Error('error')
}else{
console.log("Problem retrieving XML data:" + xmlhttp.statusText);
}
}
}
// fetch: "unhandledrejection"
// fetch: "unhandledrejection"
// xmlhttp: "addEventListener"
错误类型
Error
代码运行时的错误,除了 Error 这个对象,一些内置 错误类 在异常时返回,如SyntaxError、 EvalError 、 RangeError 、 ReferenceError 、 TypeError 等,具体信息Error
Script error.
跨域脚本,为了防止信息泄露,不会展示语法错误具体信息,只会展示 Script error.
可以先解决跨域:
- 客户端script标签添加
crossorigin="anonymous" - 服务端响应header添加
Access-Control-Allow-Origin: *
或者使用 try/catch 捕获运行方法的错误信息
SyntaxError
语法错误是无法被捕获的,因为语法错误脚本不会放入任务队列,不会继续执行这段脚本,所以也不会有事件冒泡,这个是要在开发阶段就要防范,但是使用 eval 执行却可以捕获到错误信息
try {
eval('hoo bar');
} catch (e) {
console.log(e instanceof SyntaxError); // true
console.log(e.message); // "missing ; before statement"
console.log(e.name); // "SyntaxError"
console.log(e.fileName); // "Scratchpad/1"
console.log(e.lineNumber); // 1
console.log(e.columnNumber); // 4
console.log(e.stack); // "@Scratchpad/1:2:3\n"
}
DOMException
Web API 访问和调用时错误,API报错会设置错误name,如 SyntaxError 、 NotFoundError 等,具体信息DOMException
错误事件
error
window.onerror 和 window.addEventListener('error') 是基本一样的,但是 onerror 无法捕获资源加载失败,关于onerror浏览器兼容性可以看这篇文章
// useCapture 需要设置 true
// 事件冒泡
window.addEventListener('error', (e) => {
console.log(e)
console.log(e.message)
console.log(e.source)
console.log(e.lineno)
console.log(e.colno)
console.log(e.error)
// 禁止默认错误提示
e.preventDefault();
}, true);
- message:错误信息(字符串)。可用于HTML onerror=""处理程序中的event。
- source:发生错误的脚本URL(字符串)
- lineno:发生错误的行号(数字)
- colno:发生错误的列号(数字)
- error:Error对象(对象)
unhandledrejection
The
unhandledrejectionevent is sent to the global scope of a script when a JavaScriptPromisethat has no rejection handler is rejected; typically, this is thewindow, but may also be aWorker. This is useful for debugging and for providing fallback error handling for unexpected situations.
用来捕获 Promise 未处理 reject ,但是返回的信息只有 promise 和 reason ,没有其他具体信息
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
}, true);