笔记:《JavaScript学习指南》-第11章异常和错误处理

第11章 异常和错误处理

异常处理是一种以可控的方式处理错误的机制。

11.1 Error 对象

Error是JavaScript 的内建对象,可以用来处理任意类型的错误(异常或预期错误)。

在创建Error 实例是提供一些错误信息:
const err = new Error("invalid email");

创建出的Error 实例本身不会做任何事,只提供一个传递错误的载体。
验证邮箱地址,验证成功,返回字符串格式的邮箱,否则返回Error实例:
//使用了三元运算符
function validateEmail(email){
    return email.match(/@/) ? email : new Error(`invalid email: ${email}`);
}
为了使用返回值,用typeof 运算符来判断返回的是不是 Error 实例。然后通过 Error 的message 属性来获取错误信息。
//...validateEmail函数...

const email = " 1234@abc.com";

const validatedEmail = validateEmail(email);
if(validatedEmail instanceof Error){
    console.log(`Error: ${validatedEmail.message}`);
}else{
    console.log(`valid email: ${validatedEmail}`);
}    
    // valid email: 1234@abc.com

11.2 使用 try 和 catch 处理异常

try...catch 语句可以完成异常处理。其理念是:首先“尝试”去做一些事情,一旦在做的过程中发生异常,就“捕获”这些异常。
前例中,如果某个开发人员不小心给email 赋了一个非字符串的值,将会出错。为防范这种非预期错误,可以将用于验证邮箱的代码封装在 try...catch 语句中,例如:
const err = new Error("invalid email");

function validateEmail(email){
    return email.match(/@/) ? email : new Error(`invalid email: ${email}`);
}

const email = null;

try{
    const validatedEmail = validateEmail(email);

    if(validatedEmail instanceof Error){
        console.log(`Error: ${validatedEmail.message}`);
    }else{
        console.log(`Valid email: ${validatedEmail}`);
    }
}

catch(err){
    console.log(`Error: ${err.message}`);
}
        // Error: Cannot read property 'match' of null
捕获异常后,程序就不会崩溃了,而是打印了错误日志后继续执行。
一旦有错误产生,执行逻辑就会立即跳转到 catch 块中。

11.3 抛出异常

throw 抛出异常,当调用throw时, 当前函数会立即停止执行。
例如,如果需要给一个银行应用开发付款功能,在账户余额不足的时候抛出一个异常:
function billPay(amouont, payee, account){
    if(amount > account.balance) throw new Error("insufficient funds");
    account.transfer(payee, amount);
}

11.4 异常处理和调用栈

一个标准的应用程序中会存在很多函数调用,而这些函数又会调用其他函数,继而调用更多函数。JavaScript将追踪这些函数调用。假设函数a 调用函数b,b 调用函数c,c 结束的时候,执行逻辑会返回到b,b 结束时,执行逻辑返回到c。当c 正在执行的时候,a 和b 都未完成。这种未完成的嵌套函数调用就叫做 调用栈
如果函数c 出错,b和a 也会出错。本质上,错误会沿着调用栈传递,直到被捕获。

错误可以在调用栈中的任一级别被捕获,如果它们没有被捕获,JavaScript解释器将会强行终止程序。这种错误被称为 未被处理的异常或者 未被捕获的异常

在大多数的JavaScript实现中,Error 实例包含了一个 stack 属性,它是调用栈的字符串形式。
异常处理的例子:
function a(){
    console.log("a: calling b");
    b();
    console.log("a: done");
}

function b(){
    console.log("b: calling c");
    c();
    console.log("b: done");
}

function c(){
    console.log("c: throwing error");
    throw new Error("c error");
    console.log("c: done");
}

function d(){
    console.log("d: calling c");
    c();
    console.log("d: done");
}

try{
    a();
} catch(err) {
    console.log(err.stack);
}

try{
    d();
} catch(err) {
    console.log(err.stack);
}
上面代码在谷歌控制台运行后:
a: calling b
b: calling c
c: throwing error
Error: c error
    at c (<anonymous>:15:11)
    at b (<anonymous>:9:5)
    at a (<anonymous>:3:5)
    at <anonymous>:26:5
d: calling c
c: throwing error
Error: c error
    at c (<anonymous>:15:11)
    at d (<anonymous>:21:5)
    at <anonymous>:32:5
出现 at 字符的行是栈轨迹,它会从“最深层”函数开始(c),直到没有函数调用(浏览器自身)。可以看到显示了两个不同的栈轨迹。

11.5 try...catch...finally

finally 不管是否发生错误,finally 中的代码都会被执行。
很多时候,try块中会包含一些对资源的引用,比如HTTP连接或者文件。不管有没有发生错误,都需要释放这些资源,防止应用程序永远占用着资源。因为try 块中,随时都有错误,释放资源并不安全。catch 只在错误发生时运行,释放资源也不安全。所有使用finally。
try{
    console.log("this line is executed...");
    throw new Error("whoops");
    console.log("this line is not...");
} catch(err) {
    console.log("there was an error...");
} finally {
    console.log("...always executed");
    console.log("perform cleanup here");
}
 不管有没有throw,上面例子的 finally 块中的代码均被执行了。

11.6 让异常称为例外

一旦抛出异常,就一定要捕获它,除非想让程序崩溃。
处理那些没有预期到的错误时,用控制流语句来处理预期错误,而把异常当做最后一道防线。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值