javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS try-catch异常处理机制

JS中try-catch异常处理机制详解(结合 async/await)

作者:爱吃草莓软糖

这篇文章主要介绍了JS中try-catch异常处理机制(结合 async/await)的相关资料,try...catch语句将能引发错误的代码放在try块中,并且对应一个响应,然后有异常被抛出,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

try-catch 是 JavaScript 中处理同步 / 异步异常的核心机制,尤其在 async/await 语法中,它是兜底异步错误的 “标准操作”。本文从底层机制核心用法async/await 适配常见误区四个维度,把 try-catch 讲透。

一、try-catch 基础机制:“捕获 - 处理” 的核心逻辑

1. 本质作用

try-catch 用于捕获代码执行过程中抛出的异常,避免异常向上冒泡导致程序崩溃,同时允许开发者自定义错误处理逻辑。

2. 语法结构

try {
  // 可能抛出异常的代码(同步/await 异步)
} catch (error) {
  // 只有 try 块抛出异常时,才执行这里(处理错误)
} finally {
  // 可选:无论是否抛出异常,最终一定会执行(收尾操作)
}

3. 底层执行流程

  1. 执行 try 块内的代码;
  2. 如果 try 块内没有抛出异常:跳过 catch 块,执行 finally 块(若有),然后继续执行后续代码;
  3. 如果 try 块内抛出异常:立即停止 try 块剩余代码,跳转到 catch 块,传入异常对象,执行错误处理逻辑;执行完 catch 后,再执行 finally 块(若有);
  4. finally 块是 “最终保障”:即使 try/catch 内有 return,也会先执行 finally 再返回。

二、try-catch 处理同步异常(基础场景)

同步代码的异常(比如变量未定义、类型错误),会立即抛出,可被 try-catch 直接捕获:

示例 1:捕获基础语法错误

function syncErrorDemo() {
  try {
    console.log("开始执行同步代码");
    // 抛出同步异常:访问未定义的变量
    console.log(nonExistVar); 
    console.log("这行代码不会执行"); // 异常后停止执行
  } catch (error) {
    // 捕获异常并解析
    console.log("捕获到同步异常:");
    console.log("错误类型:", error.name); // ReferenceError
    console.log("错误信息:", error.message); // nonExistVar is not defined
    console.log("调用栈:", error.stack); // 定位错误位置(调试关键)
  } finally {
    console.log("finally:同步代码执行收尾\n");
  }
}
 
syncErrorDemo();

执行结果

开始执行同步代码
捕获到同步异常:
错误类型: ReferenceError
错误信息: nonExistVar is not defined
调用栈: ReferenceError: nonExistVar is not defined at syncErrorDemo (...)
finally:同步代码执行收尾

示例 2:手动抛出异常(throw 关键字)

开发者可通过 throw 主动抛出异常(自定义错误),同样会被 catch 捕获:

function validateAge(age) {
  try {
    if (age < 18) {
      // 手动抛出自定义 Error 对象(推荐)
      throw new Error("年龄必须≥18岁");
    }
    console.log("年龄验证通过");
  } catch (error) {
    console.log("验证失败:", error.message);
  }
}
 
validateAge(16); // 验证失败:年龄必须≥18岁
validateAge(20); // 年龄验证通过

三、try-catch 处理异步异常(核心:适配 async/await)

1. 异步异常的特殊性

普通异步代码(比如 setTimeout 回调、Promise 回调)的异常,无法被外层同步的 try-catch 捕获—— 因为异步代码执行时,外层 try-catch 早已执行完毕:

// 错误示例:同步 try-catch 捕获不到异步回调的异常
function wrongAsyncCatch() {
  try {
    setTimeout(() => {
      // 异步回调内的异常,外层 try-catch 捕获不到
      throw new Error("异步回调出错");
    }, 1000);
  } catch (error) {
    console.log("捕获到错误:", error); // 永远不会执行
  }
}
wrongAsyncCatch(); // 控制台会抛出“未捕获的异常”

2. async/await 让 try-catch 能捕获异步异常

async/await 是 Promise 的语法糖,它将 “异步代码同步化”——await 会暂停 async 函数执行,直到 Promise 状态变更;如果 Promise 被 reject(或异步代码抛出异常),会像同步异常一样抛出,此时 try-catch 就能捕获:

核心示例:捕获 await 异步错误

// 模拟异步操作(返回 Promise)
function fetchData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === "success") {
        resolve({ data: "请求成功", code: 200 });
      } else {
        // Promise reject 会被 await 转化为同步异常
        reject(new Error("接口请求失败:404 Not Found"));
      }
    }, 1000);
  });
}
 
// async/await + try-catch 捕获异步异常
async function asyncAwaitCatch() {
  try {
    console.log("开始请求接口");
    // await 等待 Promise,若 reject 则抛出异常
    const res = await fetchData("fail"); 
    console.log("接口返回:", res); // 异常后不会执行
  } catch (error) {
    // 捕获异步异常(等同于 Promise 的 .catch())
    console.log("捕获到异步异常:", error.message);
    // 错误兜底:使用默认数据
    const defaultData = { data: "默认数据", code: 500 };
    console.log("兜底方案:", defaultData);
  } finally {
    console.log("finally:请求流程收尾(关闭加载弹窗)");
  }
}
 
asyncAwaitCatch();

执行结果

开始请求接口
捕获到异步异常:接口请求失败:404 Not Found
兜底方案: { data: '默认数据', code: 500 }
finally:请求流程收尾(关闭加载弹窗)

3. 多异步操作的异常捕获策略

场景捕获方式适用场景
串行异步(依赖执行)单个 try-catch 包裹所有 await一个失败则整体失败(比如表单提交)
串行异步(独立执行)每个 await 单独 try-catch单个失败不影响其他(比如多商品下单)
并行异步(Promise.all)try-catch 包裹 Promise.all所有操作必须成功(比如批量校验)
并行异步(允许部分失败)Promise.allSettled + 解析结果部分失败不影响整体(比如批量查询)

示例:并行异步的异常处理(Promise.all + try-catch)

async function parallelCatch() {
  try {
    // Promise.all 中任意一个 Promise reject,整体就会抛出异常
    const [res1, res2] = await Promise.all([
      fetchData("success"), // 成功
      fetchData("fail")     // 失败
    ]);
    console.log("并行请求成功:", res1, res2);
  } catch (error) {
    console.log("并行请求失败:", error.message);
    // 兜底:重新请求失败的接口
    const backupRes = await fetchData("success");
    console.log("兜底成功:", backupRes);
  }
}
parallelCatch();

四、try-catch 的关键特性与常见误区

1. 关键特性

(1)catch 只能捕获 “抛出的异常”

只有通过 throw 或 Promise reject 明确抛出的异常,才能被 catch 捕获;静默失败(比如函数返回 undefined)不会触发 catch:

try {
  const res = undefined; // 静默失败,无异常抛出
  if (!res) {
    console.log("数据为空,但未抛出异常");
  }
} catch (error) {
  console.log("不会执行这里");
}

(2)finally 块的 “优先级”

即使 try/catch 内有 return,也会先执行 finally 再返回:

function finallyPriority() {
  try {
    return "try 返回值";
  } catch (e) {
    return "catch 返回值";
  } finally {
    console.log("finally 先执行");
  }
}
console.log(finallyPriority()); // 输出:finally 先执行 → try 返回值

(3)Error 对象的核心属性

catch 捕获的 error 是 Error 实例(推荐用 new Error() 创建),包含三个核心属性:

2. 常见误区

误区 1:用 try-catch 捕获所有异步错误(包括非 await 异步)

// 错误:try-catch 捕获不到非 await 的 Promise 异常
async function wrongCatch() {
  try {
    // 未用 await,Promise 异常会“逃逸”
    fetchData("fail"); 
  } catch (error) {
    console.log("捕获不到:", error);
  }
}
wrongCatch(); // 控制台抛出未捕获的异常

解决:必须用 await 等待 Promise,才能让异常被 try-catch 捕获。

误区 2:忽略 finally 块的资源释放

// 错误:请求失败时,未关闭加载弹窗
async function noFinally() {
  console.log("打开加载弹窗");
  try {
    await fetchData("fail");
  } catch (error) {
    console.log("请求失败");
    // 忘记关闭弹窗
  }
  // 如果没有 catch,弹窗永远不会关闭
}

解决:把 “资源释放 / 收尾操作” 放在 finally 块(比如关闭弹窗、清除定时器)。

误区 3:catch 块只打印日志,不处理错误

// 低效:只打印日志,没有兜底逻辑
async function uselessCatch() {
  try {
    await fetchData("fail");
  } catch (error) {
    console.log("出错了:", error); // 仅打印,无兜底
  }
  // 后续代码依赖接口数据,会继续报错
  console.log(res.data); // res 未定义
}

解决:catch 块要做 “兜底处理”(比如赋值默认数据、重试请求、提示用户)。

五、try-catch 与 Promise.catch 的对比(async/await 场景)

在 async/await 中,try-catch 等价于 Promise 的 .catch(),但更符合 “同步思维”:

特性try-catch(async/await)Promise.catch()
代码可读性高(线性代码,无嵌套)低(链式调用)
错误处理范围可包裹多个 await 操作只能处理单个 Promise
同步 / 异步错误捕获同时支持仅支持 Promise 异常
调试体验更友好(调用栈清晰)链式调用易丢失上下文

等价示例

// 1. try-catch 写法(推荐)
async function tryCatchDemo() {
  try {
    const res = await fetchData("fail");
  } catch (e) {
    console.log("捕获错误:", e.message);
  }
}
 
// 2. Promise.catch 写法(等价)
async function promiseCatchDemo() {
  const res = await fetchData("fail").catch(e => {
    console.log("捕获错误:", e.message);
  });
}

六、总结:try-catch 核心使用原则

  1. 同步代码:所有可能抛出异常的逻辑(比如参数校验、DOM 操作),都用 try-catch 包裹;
  2. async/await 异步代码:必须用 try-catch 包裹 await 操作(或外部加 .catch()),避免未捕获的异步异常;
  3. finally 必用场景:涉及资源占用的操作(比如打开弹窗、创建定时器、请求接口),一定要在 finally 中释放 / 收尾;
  4. catch 块要 “有用”:不仅要捕获错误,还要做兜底处理(默认值、重试、用户提示),而非仅打印日志;
  5. 错误类型细化:可通过 error.name 区分错误类型,做针对性处理(比如网络错误重试、业务错误提示)。

try-catch 不是 “万能的”,但它是 JS 中最基础、最可靠的异常处理方式 —— 尤其是在 async/await 场景下,掌握它就能解决 90% 以上的异常处理问题。

到此这篇关于JS中try-catch异常处理机制(结合 async/await)的文章就介绍到这了,更多相关JS try-catch异常处理机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文