异常捕获与抛出
# 1.try...catch
try...catch 语句用于包裹可能出现意外的语句,当出现异常时抛出,不影响下面函数的执行。
try语句包含了由一个或者多个语句组成的try块, 和至少一个catch块或者一个finally块的其中一个,或者两个兼有, 下面是三种形式的try声明:
- try...catch
- try...finally
- try...catch...finally
finally 语句无论是否抛出异常都会执行
try {
try {
throw new Error("oops");
}
catch (ex) {
console.error("inner", ex.message);
throw ex;
}
finally {
console.log("finally");
}
}
catch (ex) {
console.error("outer", ex.message);
}
// Output:
// "inner" "oops"
// "finally"
// "outer" "oops"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
参考:
# 2.throw语句
throw
语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw
之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch
块。如果调用者函数中没有catch
块,程序将会终止。
语法:throw expression;
- 抛出一个
error
对象
try {
if (true) {
throw new Error('错误')
}
} catch (e) {
console.log(e);
}
// Error: 错误
2
3
4
5
6
7
8
- 抛出一个指定对象
function UserException(message) {
this.message = message;
this.name = "UserException";
}
function getMonthName(mo) {
mo = mo - 1;
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"];
if (months[mo] !== undefined) {
return months[mo];
} else {
throw new UserException("InvalidMonthNo");
}
}
try {
var myMonth = 1; // 15 超出边界并引发异常
var monthName = getMonthName(myMonth);
} catch (e) {
console.log(e.message, e.name);
}
// InvalidMonthNo UserException
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3.Error构造器
通过Error
的构造器可以创建一个错误对象。当运行时错误产生时,Error
的实例对象会被抛出。Error
对象也可用于用户自定义的异常的基础对象。
语法: new Error(描述信息, 所在文件名, 所在文件行号)
- 抛出一个基本错误
try {
throw new Error("Whoops!");
} catch (e) {
alert(e.name + ": " + e.message);
}
2
3
4
5
- 自定义异常类型
function MyError(message) {
this.name = 'MyError';
this.message = message || 'Default Message';
this.stack = (new Error()).stack;
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
try {
throw new MyError('custom message');
} catch (e) {
console.log(e.name + ':' + e.message);
}
2
3
4
5
6
7
8
9
10
11
12
13
# 其他类型
除了基础的 Error, 还有6个其他类型错误构造函数:
EvalError
:错误原因与 eval() 有关InternalError
:引擎内部抛出的实例,如"递归太多"RangeError
:数值变量或参数超出其有效范围ReferenceError
:无效引用SyntaxError
:语法错误TypeError
:变量或参数不属于有效类型URIError
:给 encodeURI()或 decodeURl()传递的参数无效
# 4.window.onerror
当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()。
语法: window.onerror = function(message, source, lineno, colno, error) { ... }
函数参数:
- message:错误信息(字符串)。可用于HTML onerror=""处理程序中的event。
- source:发生错误的脚本URL(字符串)
- lineno:发生错误的行号(数字)
- colno:发生错误的列号(数字)
- error:Error对象(对象)
若该函数返回true,则阻止执行默认事件处理函数。
window.onerror = function(message, source, lineno, colno, error) {
console.log('捕获到异常:',{message, source, lineno, colno, error});
}
2
3
# 5.window.addEventListener('error')
当一项资源(如<img
>或<script>
)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener捕获
语法:window.addEventListener('error', function(event) { ... })
window.addEventListener('error', function(event) {
console.log('捕获到异常:' + event)
}
2
3
# 6.window.addEventListener('unhandledrejection')
当Promise
被 reject
且没有被catch
时候,会触发unhandledrejection
事件;这可能发生在 window
下,但也可能发生在 Worker
中。
- 基本的异常上报
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
});
2
3
- 阻止默认处理,添加自定义处理
window.addEventListener('unhandledrejection', function (event) {
// ...您的代码可以处理未处理的拒绝...
// 防止默认处理(例如将错误输出到控制台)
event.preventDefault();
});
2
3
4
5
6
# 7.监控页面奔溃
当页面奔溃,js都无法运行时,可以使用 window 对象的 load 和 beforeunload 实现监控
window.addEventListener('load', function () {
sessionStorage.setItem('good_exit', 'pending');
setInterval(function () {
sessionStorage.setItem('time_before_crash', new Date().toString());
}, 1000);
});
window.addEventListener('beforeunload', function () {
sessionStorage.setItem('good_exit', 'true');
});
if(sessionStorage.getItem('good_exit') && sessionStorage.getIte('good_exit') !== 'true') {
/*
insert crash logging code here
*/
alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash'));
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 8.解决Script Error跨域
添加crossOrigin
属性可以解决Script Error跨域问题。cors 设置属性介绍
<script src="http://xxx.com/test.js" crossorigin></script>
# 9.Vue异常捕捉-errorHandler
errorHandler
指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
// 只在 2.2.0+ 可用
}
2
3
4
5
# 10.总结
- 可疑区域增加: try...catch
- 全局监控JS异常: window.onerror
- 全局监控静态资源异常: window.addEventListener
- 全局捕获没有 catch 的 promise 异常:unhandledrejection
- 监控网页崩溃:window 对象的 load 和 beforeunload
- Script Error跨域: 添加 crossOrigin 属性
- VUE 异常捕获:errorHandler
- React 异常捕获:componentDidCatch