在介绍 JavaScript try...catch...finally 语句之前,我们先来看一个简单的例子。
示例 1:没有使用 try...catch
function add(a, b) {
return a + b;
}
// 第 1 次计算
const num1 = 50;
const num2 = JSON.parse("abc");
console.log(add(num1, num2));
// 第 2 次计算
console.log(add(10, 20));运行结果如下。
(报错)SyntaxError: Unexpected token 'a', "abc" is not valid JSON分析:
在这个例子中,我们首先定义了一个名为 “add” 的函数,用于计算两个数的和。然后尝试调用 2 次 add() 来进行计算。但是在第 1 次计算的时候,由于 JSON.parse() 解析会报错,然后导致后面所有的程序都执行不了了,包括第 2 次计算。
如果希望在第 1 次计算的时候,即使报错也不会影响后面的程序(比如第 2 次计算),此时应该怎么办呢?这个时候就可以使用 try...catch 语句来解决这个问题。
JavaScript try...catch 语句
在 JavaScript 中,我们可以使用 try...catch 语句来测试一段可能出错的代码,并且在出错的时候捕获到这个错误,从而防止程序崩溃,影响后面程序的执行。
语法:
try {
// 可能出错的代码
} catch (error) {
// 出错时如何处理
}分析:
对于 try...catch 语句来说,它主要由 2 部分组成:
- try 块:用于包含可能出错的代码。
- catch 块:它接收一个参数(通常命名为 error),代表抛出的异常对象。
也就是说,如果 “try 块” 报错了,就会去执行 “catch 块” 代码,并且也不会影响后面程序的执行。
示例 2:使用 try...catch 处理
function add(a, b) {
return a + b;
}
try {
// 第 1 组
const num1 = 50;
const num2 = JSON.parse("abc");
console.log(add(num1, num2));
} catch (error) {
console.log(error.name);
console.log(error.message);
}
// 第 2 组
console.log(add(10, 20));运行结果如下。
SyntaxError
Unexpected token 'a', "abc" is not valid JSON
30分析:
对于这个例子中,try 块执行到 const num2 = JSON.parse("abc"); 这一句代码时,会抛出 SyntaxError 异常。需要注意的是,此时 JavaScript 会立即停止执行 try 块中 “剩余的代码”,并跳转到 catch 块中。
当 catch 块中的代码执行完成之后,JavaScript 会继续执行 try...catch 之后的代码,从而避免异常代码导致整个程序崩溃。
error 是一个错误对象(也叫 “异常对象”),它主要包含 2 个属性:
name:错误的类型名称,比如:SyntaxError、TypeError、ReferenceError 等。message:错误的详细信息。
JavaScript try...catch...finally 语句
在处理 JavaScript 异常时,如果希望 try 代码块不管有没有发生异常,都继续执行某些语句,我们可以使用 finally 子句来实现。
语法:
try {
// 可能出错的代码
} catch (error) {
// 出错时如何处理
} finally {
// 无论是否发生异常,这部分代码都会执行
}说明:
finally 子句一般用于执行清理工作,比如关闭文件连接、释放资源、重置变量等。
示例 3:try...catch...finally 基本用法
async function fetchUserData() {
let isLoading = true; // 开始动画
console.log("正在加载...");
try {
// 假设这里是一个接口请求,这里用 Promise 模拟
let response = await fakeFetch();
console.log("用户数据:", response);
} catch (error) {
console.log("获取失败:", error.message);
} finally {
isLoading = false; // 不管成功失败,都停止动画
console.log("加载结束");
}
}
// 模拟网络请求函数
function fakeFetch() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: 1, name: "张三" });
}, 1000);
});
}
fetchUserData();运行结果如下。
正在加载...
用户数据: {"id":1,"name":"张三"}
加载结束分析:
try...catch...finally 最常见的场景之一,就是用于处理 AJAX 请求中的动画。就拿咱们绿叶网的 “Java 在线编译器” 来说,当点击【运行代码】按钮之后,会设置动画的开始(let isLoading = true;),然后就会向服务器发起一个请求。然后我们希望不管这个请求是成功还是失败,都要停止动画(isLoading = false;)。此时就需要使用 finally 子句来实现。
这个使用场景非常经典,也非常有用,小伙伴们要多加斟酌理解一下。
JavaScript try...catch...finally 应用场景
在 JavaScript 中,try...catch...finally 语句主要使用场景,就是可以使得我们的程序在遇到错误时能够优雅地失败,而不是完全崩溃。它的主要应用场景包括:
1. 处理不确定的数据(比如用户输入)
表单中用户的输入数据,从网络或文件拿到的数据(比如 JSON 格式),可能会出现格式不规范等问题,此时会导致程序直接崩溃。
像这样可能出错的数据,最好的办法是使用 try...catch 语句来处理。如果失败了(比如不是一个有效的 JSON 格式),程序就不会崩溃,而是会执行 catch 里面的代码,友好地提示用户。
try {
// 尝试把用户的输入当成 JSON 来解析
let data = JSON.parse(userInput);
} catch (error) {
// 如果解析失败了,就执行这里面的代码
console.log("输入格式不正确");
}2. 处理 AJAX 请求
从网络上获取数据(比如发送 AJAX 或 Fetch 请求)时,可能会遇到各种网络问题,例如断网、服务器宕机、请求超时等等,这些都可能导致程序出错。
我们可以尝试在 “try 块” 中发送请求并等待结果,如果网络连接或请求本身发生错误(而不是服务器返回的错误状态码,而是网络连接上的错误),就在 “catch 块” 中捕获它,然后给用户一个友好的提示。
try {
// 尝试连接并获取数据
const res = await fetch("https://api.example.com/user");
} catch (error) {
// 如果网络连接失败了,就执行这里面的代码
console.log("网络连接失败,请检查网络后重试。");
}3. 处理本地存储(localStorage)
如果我们想在浏览器里本地存储一些数据 (localStorage),但在一些特殊情况下,比如用户禁用了存储功能,或者存储空间满了,此时尝试存储或读取数据会抛出错误。
我们可以在 “try 块” 中尝试去读取或写入本地存储,如果这个操作因为权限或空间问题而失败,此时 “catch 块” 就会捕获到错误,防止程序卡住,并可以告诉用户发生了什么。
try {
// 尝试从本地存储中获取数据
let data = localStorage.getItem("data");
} catch (error) {
// 如果因为某些限制导致操作失败,就执行这里面的代码
console.log("获取数据失败,可能是你禁用了存储功能。");
}总而言之一句话,就是:try...catch...finally 语句适用于那些 “可能失败但不希望影响整个程序” 的代码。
