try-catch 错误处理
说明 throw/try/catch/finally 的控制流、异步错误边界,以及何时把错误变成返回值或上报。
#howto
#growing
#dev
#javascript
[!info] related notes
- 所属:语言基础 / 阶段三
- 相关:Promise · async/await · null/undefined
try-catch 错误处理
这个概念为什么出现
库存接口失败、JSON 解析失败、权限不足——若让异常裸奔,UI 白屏;若全部吞掉,故障不可见。try/catch 是同步(及 await)路径上的结构化错误边界。
[!abstract] 一句话理解 throw 中断正常路径;catch 捕获该执行路径中的抛出,是否可恢复由代码判断;离开 try/catch 时先执行 finally。
最小可运行示例
场景:解析导入的 SKU JSON 文件
function parseSkuJson(text) {
try {
const data = JSON.parse(text)
if (!data || typeof data.sku !== 'string') {
throw new Error('SKU 字段缺失')
}
return { ok: true, data }
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : String(err) }
} finally {
// 教学点:释放临时状态/打点;不要在 finally 里 return 掩盖结果
console.log('parseSkuJson finished')
}
}
console.log(parseSkuJson('{"sku":"A-01"}'))
console.log(parseSkuJson('{'))
异步边界
async function load() {
try {
const response = await fetch('/api/x')
if (!response.ok) throw new Error(`HTTP ${response.status}`)
return await response.json()
} catch (e) {
// 可在这里添加上下文;示例继续传播,避免吞掉错误。
throw new Error('加载接口数据失败', { cause: e })
}
}
// load() 的调用方仍需 await/catch 处理它返回的 Promise
fetch 对 HTTP 404/500 通常仍 resolve,需检查 response.ok;网络失败、响应体解析失败等通过 rejection 传播。try/catch 不会自动接住稍后 timer 回调中的 throw 或未 await 的 Promise rejection。
return promise 会把 Promise 交给调用方,本地 catch 不会捕获其后续拒绝;若需要在当前 try 内处理,应 return await promise。
finally 的正常完成保留原结果;其中 return/throw 会覆盖原来的返回或异常。它不是进程退出、页面关闭或无限挂起时的持久清理保证。
工程实践
- 区分可恢复与不可恢复
- 错误信息带上下文(SKU id、请求号)
- 不要空 catch
- UI 层转用户可读,日志层保留技术细节
本节总结
try/catch 是控制流工具,不是日志框架;与 Promise/async 边界一起设计才完整。
自测题
- finally 里 return 有何风险?
- 为什么 try/catch 包
fetch().then()不够?
参考答案
- 会覆盖此前的返回值,也可把原本抛出的异常变成正常返回;finally 中再次 throw 则替换原异常。\
- then 异步,错误在后续微任务;需 await 或 catch。