愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

Javascript学习总结——异常处理

同大多数语言一样,Javascript也有异常处理机制。通过使用try...catch...finally块的方式来更优雅地处理异常

一、基本语法

使用异常处理,主要有三种形式:try..catch..try..finally..try..catch..finally,通常将要执行的代码写在try块里,而处理错误的代码写在catch块里,finally块里代码,则无论是否发生异常,都会执行。

try {
    throw new Error();
} catch(e) {
    console.log(e);
}

其中,catch块是携带一个参数的,这个参数则记录了发生错误的信息
注意: 一个异常处理块,必须至少要有catch块finally块中的一个


二、无条件与条件catch语句

无条件catch语句,指的是只要try块中的代码发生异常,都会被catch块捕获(如上述代码)。而有条件的catch快就只有当异常符合对应条件的时候才会被捕获,如:

try {
    // Exception
} catch(e) {
    if(e instanceof TypeError) {
        // 
    } else if(e instanceof ReferenceError) {
        //
    }
}



三、主动抛出错误

可以使用throw expression;的形式抛出异常,当抛出异常后,当前块中在throw expression;后的语句将不被执行,并且转而去执行catch块中的语句。

  • expression可以是任意数据类型,如string、number等,这也是catch(e)e的内容,但是通常抛出错误对象
  • 如果当前异常无法处理,可以在catch块中捕获后,使用throw e;的形式重新抛出


四、嵌套的异常处理语句

异常处理语句是可以嵌套使用的,但是这儿就存在一个异常传播的问题:
1、如果内部异常处理语句中没有定义catch块,那么异常就会被外部try块捕获,如:

try {
    try {
        throw new Error("Test");
    } finally {
        console.log("Finally");
    }
} catch(e) {
    console.log("Outer ", e.message);
}
// 输出:
// Finally
// Outer Test

2、如果内部异常处理语句定义了catch块,那么异常就会被自身的catch块捕获,而不会被外部catch块捕获,如:

try {
    try {
        throw new Error("Test");
    } catch(e) {
        console.log("Inner ", e.message);
    }
} catch(e) {
    console.log("Outer ", e.message);
}
// 输出:Inner Test

3、如果想要让外部异常处理语句捕获到异常,则可以将异常再抛出,如:

try {
    try {
        throw new Error("Test");
    } catch(e) {
        console.log("Inner ", e.message);
        throw e;
    }
} catch(e) {
    console.log("Outer ", e.message);
}
// 输出:
// Inner Test
// Outer Test

4、总结而言:,当一个try块中发生异常的时候,异常会被离它最近的catch块捕获,且只捕获一次


五、异步错误捕获

Javascript引擎是事件驱动的,代码总是以单线程执行。回调函数的执行是放到了Event Loop队列中,只有等到下一个满足条件的事件出现后,才会被执行

基于Javascript的机制,尝试执行如下代码:

setTimeout(function(){ 
    console.log("World");
}, 0);
console.log("Hello");

可以发现,输出结果是Hello World,知道了这个情况后,再看如下代码:

try {
    setTimeout(() => {
        throw new Error();
    }, 0);
    console.log("TEST");
} catch(e) {
    console.log("Hello");
}

运行后,会发现catch块中的语句并没有得到执行。分析如下:
因为Javascript的事件循环机制,所以setTimeout是在调用它的语句执行完之后才执行的,而当它执行的时候,已经脱离了try..catch块了,它的错误自然无法被捕获,也就是说,以上代码,相当于:

try {
    console.log("TEST");
} catch(e) {
    console.log("Hello");
}
throw new Error();

如果要解决这个问题,处理方法就是将异常处理语句写在回调函数里