错误处理

Completion Record

关于 Completion Record,可以学习 Winter 的这篇文章:JavaScript执行(四):try里面放return,finally还会执行吗?open in new window

控制语句与 break 、continue 、return 、throw 结合

“穿透”就是指不在当前这一层处理,向外逐层寻找可以“消费”的那一层,直到最后都没找到就报错,比如:function里面有whilewhile里面有switchswitch里面又有continue,按图表来看,switch-continue应该是穿透,向上层寻找消费,碰到while-contine,那就是消费,再如switch里面是returnswitch-return穿透,向上层whlie-return穿透,最后function-return是消费。

自定义错误

class ValidationError extends Error {
    constructor(message) {
        super(message);
        this.name = "ValidationError";
        this.customProperty = 'customProperty'; // 这里还可以添加自定义属性
    }
}

try {
    throw new ValidationError('this is a ValidationError');
} catch(error) {
    console.log('error.name:', error.name);
    console.log('error.message:', error.message);
    console.log('error.customProperty:', error.customProperty);
    console.log('error.stack:', error.stack)
}

// 打印结果
// error.name: ValidationError
// error.message: this is a ValidationError
// error.customProperty: customProperty
// error.stack: ValidationError: this is a ValidationError
//     at <anonymous>:10:11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

以上的实现里,新实现的错误类ValidationErrorname属性是通过this.name = "ValidationError";手动赋值的,如下实现可以根据自定义类的类型自动改写name属性。

// 创建自定义错误的基类
class CustomError extends Error {
    constructor(message) {
        super(message);
        this.name = this.constructor.name;
    }
}

// 基于自定义基类 CustomError,再实现新的子类
class ChildCustomError extends CustomError {
    constructor(message) {
        super(message);
        this.customProperty = 'customProperty';
    }
}

try {
    throw new ChildCustomError('this is a ChildCustomError');
} catch(error) {
    console.log('error.name:', error.name);
    console.log('error.message:', error.message);
    console.log('error.customProperty:', error.customProperty);
    console.log('error.stack:', error.stack)
}

// 打印结果
// error.name: ChildCustomError
// error.message: this is a ChildCustomError
// error.customProperty: customProperty
// error.stack: ChildCustomError: this is a ChildCustomError
//     at <anonymous>:18:11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

注意,在CustomError里的this.constructor指的是最终new操作符作用的那个类,此例里是ChildCustomError

包装异常

有时我们想要针对多个错误做统一处理,但是仍想保留原始的错误,这种情景下可将错误进行一层封装。

class CustomError extends Error {
    constructor(message, originError) {
        super(message);
        this.name = 'ParentError';
        this.originError = originError;
    }
}

function fn() {
    try {
        // doSomething() ...
    } catch (err) {
        if (err instanceof ReferenceError) {
            throw new CustomError('ReferenceError', err)
        } else if (err instanceof TypeError) {
            throw new CustomError('TypeError', err)
        } else {
            throw new CustomError('OtherError', err)
        }
    }
    // ...
}


try {
    fn()
} catch (err) {
    if (err instanceof CustomError) {
        // 处理 CustomError 错误
        // console.log(err.originError)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

参考文档