认识
一、代码执行异常
1.1 错误类型
-
Error
: 最基本的错误类型,其他的错误类型都继承自该类型。通过Error
,我们可以自定义Error
类型。 -
RangeError
: 范围错误。当出现堆栈溢出(递归没有终止条件)、数值超出范围(new Array
传入负数或者一个特别大的整数)情况时会抛出这个异常。 -
ReferenceError
: 引用错误。当一个不存在的对象被引用时发生的异常。 -
SyntaxError
: 语法错误。如变量以数字开头;花括号没有闭合等。 -
TypeError
: 类型错误。如把number
当str
使用。 -
URIError
: 向全局URI
处理函数传递一个不合法的URI
时,就会抛出这个异常。如使用decodeURI('%')
、decodeURIComponent('%')
。 -
EvalError
: 一个关于eval
的异常,不会被javascript
抛出。
1.2 try catch
try{}catch(){}
能捕捉到的异常必须是线程执行已经进入 try catch
但 try catch
未执行完的时候抛出来的。当程序运行到 try catch
里面时,如果未报错,则忽略 catch
中的代码,若报错,则不执行 try
报错内容后面的代码,转而执行 catch
中的代码。try{}catch(){}
有如下特点:
-
无法捕获语法错误: 因为语法错误是在语法检查阶段就报错了,线程执行尚未进入
try catch
代码块,自然就无法捕获到异常。 -
无法捕获异步错误: 因为等异步函数里面的事件进入事件队列的时候,主线程已经离开了
try catch
,所以try catch
是无法捕获异步函数的错误的。 -
无法捕获
Promise
异常: 当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在try-catch
所在的栈,所以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');
}
1.3 window.onerror
window.onerror
事件在冒泡阶段执行, 用于全局捕获错误。 window.onerror
得到了五个参数,获取的报错堆栈相对很完整。 window.onerror
可以捕获异步错误; 捕获不到静态资源加载异常的错误,原因是资源类型错误没有冒泡,只能在捕获阶段捕获,而 window.onerror
是通过在冒泡阶段捕获错误,对静态资源加载类型异常无效,所以只能借助 window.addEventListener('error', callback, true)
的方式捕获。
语法
window.onerror = function(message, source, lineno, colno, error) { ... }
-
message
:错误信息(字符串)。可用于HTMLonerror
=处理程序中的event
。 -
source
:发生错误的脚本URL
(字符串) -
lineno
:发生错误的行号(数字) -
colno
:发生错误的列号(数字) -
error
:Error
对象
示例
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);
1.4 window.addEventListener("error")
window.addEventListener('error', true)
用于在捕获阶段全局捕获错误。可以捕获异步错误、可以捕获网络异常、静态资源加载异常错误。但是通过 window.addEventListener('error', true)
获取的报错堆栈不是很完整。
window.addEventListener("error", function (event) {
const { error } = event;
console.log("error: ", error.message);
console.log("error: ", error.stack);
});
二、Promise 异常
2.1 promise().catch()
Promise.reject(); // Uncaught (in promise) undefined
2.2 window.onrejectionhandled
当Promise
被reject
并且错误信息已经被catch
处理的时候,这个错误不会被window.onerror
以及window.addEventListener("error",handler,true)
捕获。但是有专门的rejectionhandled
事件方法进行捕获处理
语法
Promise.reject(); // Uncaught (in promise) undefined
2.3 window.onunhandledrejection
当Promise
被reject
并且错误信息没有被catch
处理的时候,这个错误不会被window.onerror
以及window.addEventListener("error",handler,true)
捕获。但是有专门的unhandledrejection
事件方法进行捕获处理
语法
Promise.reject(); // Uncaught (in promise) undefined
2.4 window.addEventListener("rejectionhandled")
当Promise
被reject
并且错误信息已经被catch
处理的时候,这个错误不会被window.onerror
以及window.addEventListener("error",handler,true)
捕获。但是有专门的rejectionhandled
事件方法进行捕获处理
语法
window.addEventListener("rejectionhandled", event => {
console.log("Promise rejected; reason: " + event.reason);
}, false);
window.onrejectionhandled = ()=>{
}
Promise.reject(throw new Error("xxx")).catch(error=> { console.log(error) });
2.5 window.addEventListener("unhandledrejection")
当Promise
被reject
并且错误信息没有被catch
处理的时候,这个错误不会被window.onerror
以及window.addEventListener("error",handler,true)
捕获。但是有专门的unhandledrejection
事件方法进行捕获处理
语法
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
});
window.onunhandledrejection = event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
};
Promise.reject(throw new Error("xxx"));