很多人写 async/await 的时候,都在纠结一件事:到底要不要加 try catch?
不加吧,怕报错。加了吧,代码里到处是 try catch,看着就烦。
今天咱们就把这个事情说清楚。
先看一个常见写法
const getData = async () => {
try {
const res = await fetch('/api/user')
const data = await res.json()
return data
} catch (error) {
console.log('出错了', error)
}
}
这个写法没错。但你要是每个请求都这么写,代码就废了。
不加 try catch 会怎样?
const getData = async () => {
const res = await fetch('/api/user')
const data = await res.json()
return data
}
如果请求失败,或者接口返回的不是 JSON,整个函数就会抛出一个错误。谁调用它,谁就会收到这个错误。
你要是没在外面接住,页面可能就白屏了。
什么时候可以不加?
情况一:调用的时候再处理
// 函数里面不加
const getData = async () => {
const res = await fetch('/api/user')
return res.json()
}
// 调用的时候再加
const run = async () => {
try {
const data = await getData()
// 处理数据
} catch (error) {
// 统一处理错误
}
}
这样写的好处是,错误处理集中在一个地方,不用每个函数里面都写 try catch。
情况二:错误无所谓,不影响页面
有些请求失败了也没关系。比如你请求一个推荐内容,失败了就失败了,页面其他地方还能正常用。
const getRecommend = async () => {
const res = await fetch('/api/recommend')
return res.json()
}
// 没人管它报不报错,报错也不影响主要功能
情况三:用全局错误处理
Vue 或者 React 项目里,你可以挂一个全局的错误捕获。
// Vue 3 例子
app.config.errorHandler = (err) => {
console.log('全局抓到错误了', err)
}
这时候很多异步函数就不用单独加 try catch 了,全局会帮你兜底。
什么时候一定要加?
情况一:要做用户提示
请求失败了,你得告诉用户“网络不好,等会儿再试”。这个提示逻辑必须写在 try catch 里。
const submitForm = async () => {
try {
await api.submit(formData)
showToast('提交成功')
} catch {
showToast('提交失败,再试一次')
}
}
情况二:失败后要做补救
比如请求用户信息失败了,你得用一份默认数据顶着,不能让页面崩掉。
const getUserInfo = async () => {
try {
const res = await fetch('/api/user')
return await res.json()
} catch {
// 失败了就给一个默认数据
return { name: '访客', avatar: 'default.jpg' }
}
}
情况三:需要做重试
请求失败了,要自动再试三次。这个重试逻辑只能在 catch 里面写。
const requestWithRetry = async (url, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
const res = await fetch(url)
return await res.json()
} catch (err) {
if (i === retries - 1) throw err
// 等一秒再试
await new Promise(r => setTimeout(r, 1000))
}
}
}
这个必须加 try catch,不加你没法知道失败了几次。
一个好用的封装
要是你不想每个地方都写 try catch,可以封装一个工具函数。
const safeRequest = async (promise) => {
try {
const data = await promise
return [data, null]
} catch (error) {
return [null, error]
}
}
// 用起来就是这样
const [data, err] = await safeRequest(fetch('/api/user'))
if (err) {
// 处理错误
return
}
// 用 data 做事情
这样就不用写 try catch 了,用 if 判断就行。很多项目都这么干。
实际项目里怎么做?
我的习惯是这样的:
- • 工具函数、底层请求函数,不加 try catch,让错误往上抛
- • 页面里的主要请求,加 try catch,因为要给用户提示
这个规则不复杂,用熟了自然就知道什么时候该加什么时候不该加。
别听网上说的“必须加”或者“不用加”。加不加,看你需不需要在这个地方处理错误。需要就加,不需要就不加。
该文章在 2026/4/24 10:59:13 编辑过