一、基本概念
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);
}
}, [])
五、最佳实践与常见误区
- 避免滥用:仅处理可预测的异常(如网络请求,数据解析,调用返回的不确定的数据时)
- 错误日志:在catch中记录错误信息(如发送至监控平台)
- finally的使用:清理资源(关闭loading状态), 释放资源等
- 不要忽略错误,空catch块会存在隐藏问题,需至少记录错误
六、举个try/catch使用的🌰
1、背景
电商平台支付功能,用户提交订单后需要调用第三方支付接口(如支付宝/微信支付)。支付流程涉及网络请求、异步回调、支付状态轮询等操作,任何一个环节出错都可能导致支付失败。以下是使用 try/catch
解决支付异步请求异常的案例。
2、 问题分析
- 网络请求不稳定:用户点击支付按钮后,前端需要调用后端接口获取支付凭证。若网络中断或接口超时,需捕获错误并提示用户。
- 第三方支付回调异常:支付成功后,第三方平台可能异步通知失败(如回调地址不可达)。
- 支付状态轮询失败:前端需轮询后端以确认支付结果,若轮询接口异常需终止流程。
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);
}
}