06/18 10:32
相关文章
【第1641期】异常处理,"try..catch"
【第1643期】自定义错误及扩展错误
笔记梳理
使用
以 JSON.parse 方法为例
let json = '{ "age": 30 }'; // 不完整的数据
try {
let user = JSON.parse(json); // <-- 没有异常
if (!user.name) {
throw new SyntaxError("Incomplete data: no name"); // (*)
}
alert( user.name );
} catch(e) {
alert( "JSON Error: " + e.message ); // JSON Error: Incomplete data: no name
} finally {
alert( 'finally' );
}
原则及细节
1. try...catch
try...catch 只能处理有效代码之中的异常。这类异常被称为 “runtime errors”。
如果一个异常是发生在计划中将要执行的代码中,例如在 setTimeout 中,那么 try...catch 不能捕捉到。因为函数本身要稍后才能执行,这时引擎已经离开了 try..catch 结构。
2. rethrowing
当异常不想在这层处理时,抛出给外层处理
3. 自定义异常
继承自内置的 Error 类,方便使用 instanceof 检测 Error 类型
自定义基础异常类:直接使用构造器的名称作为异常的名称,这样就不用每自定义一个异常类型,都要定义一次名称
class MyError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
包装高级别异常:将低等级异常细节包装在高级别异常的属性中,这样外层代码只需处理高级别异常,无需分别处理低级别异常
// ReadError 异常类
class ReadError extends Error {
constructor(message, cause) {
super(message);
this.cause = cause;
this.name = 'ReadError';
}
}
// 使用 ReadError 抛出异常
function readUser(json) {
let user;
try {
user = JSON.parse(json);
} catch (err) {
if (err instanceof SyntaxError) {
throw new ReadError("Syntax Error", err);
} else {
throw err;
}
}
try {
validateUser(user);
} catch (err) {
if (err instanceof ValidationError) {
throw new ReadError("Validation Error", err);
} else {
throw err;
}
}
}
// 外层处理 ReadError
try {
readUser('{bad json}');
} catch (e) {
if (e instanceof ReadError) {
alert(e);
// 原错误:语法错误:在位置 1 处不应有 b
alert("Original error: " + e.cause);
} else {
throw e;
}
}
业务思考
- 业务中注意一些可能会导致异常的代码用 try...catch 包裹,使代码健壮性更好+易于调试
- 业务中使用全局 catch,主要目的是方便调试
- 扩展异常时注意继承,方便根据异常类型判断
思维导图