聊一聊前端日常使用的try...catch...finally

一、基本概念

try/catch 是 JavaScript 的异常处理机制,用于捕获代码执行中的错误,防止程序因未处理异常而崩溃。基本结构如下:

js 复制代码
try { 
// 可能抛出错误的代码
} catch (error) {
// 异常处理逻辑
} finally {
// 无论是否出错都会执行的代码(可选)
}
  • try 块:包裹可能引发异常的代码,如网络请求、数据解析等。
  • catch 块 :捕获异常,error 参数包含错误信息(如 message, stack)。
  • finally 块:用于释放资源或执行清理操作(如关闭文件、重置状态)

二、错误类型分类与处理

1、内置的错误类型

javascript提供多种内置的错误类型,常见包括

  • Error通用错误类型
  • SyntaxError语法错误,比如未闭合的标签。
  • TypeError类型错误,比如调用不存在的方法
  • ReferenceError引用错误,比如访问未定义的变量。
  • 自定义错误 :通过 throw new Error("自定义消息") 抛出

2、判断错误的类型

通过instanceof区分错误类型,实现精细化处理

js 复制代码
try{
  //...
}catch(error){
  if(error instanceof TypeError){
    console.log('类型错误', error.message)
  }else if(error instanceof SyntaxErroe){
    console.log('语法错误', error.stack)
  }
}

三、异步场景下的异常处理

1、Promise链式调用

  • 同步错误:try/catch可直接捕获async/await中的错误
js 复制代码
async function fetchData(){
  try{
    const res = await fetch('api/getdata.do');
    const data = await res.json();
  }catch(error){
    console.error("请求失败:", error);
  }
}
  • 异步错误:异步宏任务/微任务 setTimeout或者是原生的Promise需要在内部处理错误,因为外层的try/catch无法捕获异步回调。
js 复制代码
fetch('api/getdata.do').then(result){
  //...
}.catch(error){
 //...
}

2、异步错误捕获示例

js 复制代码
// 正确做法:在异步函数内部处理 
setTimeout(() => {
  try { throw new Error("已捕获的异步错误");
} catch (error) {
  console.error(error);
  }
}, 1000);

3、useEffect内部错误的捕获

如果我们直接用 try/catch 包裹 useEffect 去捕获他内部的错误是无法生效的,因为 useEffect 是异步调用的,他会在组件渲染之后才会执行,但是 try/catch 是同步执行的,所以从 try/catch 的角度来看都是成功的,因此为了捕获 useEffect 内部的错误,try/catch 也应该放在里面,代码示例

js 复制代码
useEffect(() => {
  try { throw new Error('balabala');
} catch(e) {
  // 对异常做一些处理
  }
}, [])

四、前端框架中的应用

1、vue.js

  • watch 监听器 :在数据变化处理逻辑中包裹 try/catch,防止因异常导致组件崩溃:
js 复制代码
watch: {
  dataKey(newVal) { 
  try { 
    // 复杂逻辑或外部 API 调用 
  } catch (error) {
    this.$toast.error("操作失败"); 
    }
  }
}

2、React

  • 错误边界(Error Boundaries) :通过生命周期方法捕获子组件树错误,需结合 try/catch 实现局部容错:(可以捕获 useEffect 以及子组件中的错误,但它不会捕获异步代码和事件处理程序中的错误)
js 复制代码
class ErrorBoundary extends React.Component {
  componentDidCatch(error, info) {
    console.error("组件错误:", error); 
  } render() {
    return this.props.children; 
  } 
}
  • Hooks 中的错误处理 :在 useEffect 内部使用 try/catch
js 复制代码
useEffect(() => {
  try { 
    fetchData(); 
  } catch (error) {
    setErrorState(true); 
  } 
}, [])

五、最佳实践与常见误区

  1. 避免滥用:仅处理可预测的异常(如网络请求,数据解析,调用返回的不确定的数据时)
  2. 错误日志:在catch中记录错误信息(如发送至监控平台)
  3. finally的使用:清理资源(关闭loading状态), 释放资源等
  4. 不要忽略错误,空catch块会存在隐藏问题,需至少记录错误

六、举个try/catch使用的🌰

1、背景

电商平台支付功能,用户提交订单后需要调用第三方支付接口(如支付宝/微信支付)。支付流程涉及网络请求、异步回调、支付状态轮询等操作,任何一个环节出错都可能导致支付失败。以下是使用 try/catch 解决支付异步请求异常的案例。

2、 问题分析

  1. 网络请求不稳定:用户点击支付按钮后,前端需要调用后端接口获取支付凭证。若网络中断或接口超时,需捕获错误并提示用户。
  2. 第三方支付回调异常:支付成功后,第三方平台可能异步通知失败(如回调地址不可达)。
  3. 支付状态轮询失败:前端需轮询后端以确认支付结果,若轮询接口异常需终止流程。

3、解决方案与代码实现

使用 try/catch 处理支付请求与状态轮询

js 复制代码
// React 项目中的支付按钮逻辑 async function handlePayment(orderId) { 
  try { 
    // 1. 显示加载状态 
    setLoading(true); 
    // 2. 获取支付凭证(可能因网络中断或服务端错误失败) 
    const { paymentToken } = await fetchPaymentToken(orderId);     // 3. 调用第三方支付SDK(如支付宝) 
    const result = await thirdPartyPaymentSDK(paymentToken);       // 4. 轮询支付结果(可能因轮询超时失败) 
    await pollPaymentStatus(orderId, 5000); // 5秒超时 
    // 5. 支付成功逻辑 
    showSuccessToast("支付成功!"); 
    navigateToOrderDetail(); 
  } catch (error) {
    // 捕获所有异步错误并分类处理 
    if (error instanceof NetworkError) { 
      // 网络错误(如 fetchPaymentToken 失败) 
      showErrorToast("网络异常,请检查连接"); 
    } else if (error instanceof PaymentRejectedError) {
      // 支付被拒绝(如用户取消支付) 
      showErrorToast("支付已取消"); 
    } else if (error.name === 'AbortError') {
      // 轮询超时(自定义AbortController触发) 
      showErrorToast("支付状态确认超时,请查看订单");
    } else { 
      // 未知错误兜底处理 
      logErrorToServer(error); 
      // 上报错误日志 
      showErrorToast("支付失败,请联系客服"); 
      }
    } finally {
      // 无论成功与否,关闭加载状态 setLoading(false);
      } 
    }
相关推荐
禅思院1 小时前
AI对话前端从入门到崩溃:一个长对话引发的五层优化战争【引子】
前端·面试·架构
TrisighT1 小时前
Electron 鸿蒙 PC 上点外链唤醒应用,我试了 6 种写法只有 1 种能跑
前端·electron·harmonyos
天才熊猫君2 小时前
配置与数据分离:一种可视化搭建的属性编辑方案
前端·javascript
林希_Rachel_傻希希2 小时前
web性能之相关路径——AI总结
前端·javascript·面试
掘金小豆2 小时前
Spring 事务失效的 6 大场景,你踩过几个?
后端·spring·面试
不好听6132 小时前
从零搭建一个 RAG 语义搜索系统 —— DEMO的初始阶段
javascript·面试·llm
何时梦醒3 小时前
上下文工程(Context Engineering):AI 应用开发的新范式 —— 从理论到实战全解析
javascript
竹林8183 小时前
用 wagmi v2 踩坑两天,我终于搞懂了多链钱包切换在 DeFi 前端中的正确姿势
前端·javascript
用户2136610035723 小时前
Vue项目搜索功能与面包屑导航
前端·javascript
星栈3 小时前
LiveView 的实时通信,爽是爽,但 PubSub 和广播也最容易把自己绕晕
前端·前端框架·elixir