【try/catch/Promise】【前端错误处理】从【异常捕获逻辑】到【落地实操】彻底搞懂前端错误处理的最佳写法避开异步捕获、HTTP状态码判断高频坑 文章目录开篇一、先搞清楚try/catch到底能抓到啥1.1 能抓到的同步代码里的异常1.2 抓不到的异步里的错误二、Ajax错误别只盯着try/catch2.1 fetch 是什么小白必读2.2 常见误解2.3 正确做法三、JSON 解析错误最容易漏掉的一类3.1 常见场景3.2 推荐写法四、业务异常 vs 系统异常分类处理4.1 业务异常可预期的“业务失败”4.2 系统异常程序/环境错误4.3 实战示例五、实战中的几条规范5.1 该用try/catch的地方5.2 不要指望try/catch的地方5.3 一个完整的小案例六、总结 本系列专栏导航同学们好我是 Eugene尤金一个拥有多年中后台开发经验的前端工程师~Eugene 发音很简单/juːˈdʒiːn/大家怎么顺口怎么叫就好你是否也有过明明学过很多技术一到关键时候却讲不出来、甚至写不出来你是否也曾怀疑自己是不是太笨了明明感觉会却总差一口气就算想沉下心从头梳理可工作那么忙回家还要陪伴家人。一天只有24小时时间永远不够用常常感到力不从心。技术行业本就是逆水行舟不进则退。如果你也有同样的困扰别慌。从现在开始跟着我一起心态归零利用碎片时间来一次彻彻底底的基础扫盲。这一次我们一起慢慢来扎扎实实变强。不搞花里胡哨的理论堆砌只分享看得懂、用得上的前端干货咱们一起稳步积累真正摆脱“面向搜索引擎写代码”的尴尬。开篇前端开发中错误处理很常见接口失败、JSON 解析报错、业务失败和系统异常混在一起处理。不少人要么到处try/catch要么该用的地方没用导致线上问题难排查、用户提示不友好。用原生try/catch配合Promise/async的错误处理就能覆盖大部分场景。本文结合真实项目中的常见需求说明什么时候用try/catch、什么时候用.catch()、业务异常和系统异常如何区分只讲日常开发里 80% 会用到的情况。一、先搞清楚try/catch到底能抓到啥很多人的第一反应是try/catch能把“所有报错”都包住。实际上不是。1.1 能抓到的同步代码里的异常try{constobjJSON.parse({ invalid json });// 抛出 SyntaxErrorconsole.log(obj);}catch(e){console.error(解析失败:,e.message);// 能抓到}只要错误是在同步代码里抛出的就会被catch捕获。⬆ 返回目录1.2 抓不到的异步里的错误try{setTimeout((){thrownewError(异步报错);// 这个 catch 抓不到},0);}catch(e){console.error(e);// 不会执行}setTimeout的回调在下一个事件循环执行执行时try早就结束了所以这里的catch完全接不到这个错误。同理Promise内部的reject、Ajax的失败回调等异步错误也不能被外层的try/catch直接捕获需要用别的方式处理。⬆ 返回目录二、Ajax错误别只盯着try/catch2.1 fetch 是什么小白必读在讲Ajax错误之前先简单说一下fetch是什么这样后面的代码你才能看得懂。一句话fetch是浏览器自带的、用来向服务器发请求、拿数据的 API。可以把它理解成你在浏览器里打开页面想拿到用户列表、商品信息等服务器数据放在后端需要通过「请求」才能给你fetch就是你发请求、等回复的「工具」最基础的用法// 向 /api/user/list 这个地址发一个「我要数据」的请求constresawaitfetch(/api/user/list);constdataawaitres.json();// 把服务器返回的文本解析成 JSON 对象console.log(data);// 拿到数据了几个关键点概念大白话解释fetch(地址)向这个地址发请求默认是 GET取数据返回值是一个Promise所以要用await等它完成res服务器返回的「响应对象」里面有状态码、响应体等res.json()把响应体当成 JSON 解析返回一个 JS 对象res.text()把响应体当成普通文本返回字符串和 Ajax 的关系以前大家用XMLHttpRequest或jQuery的$.ajax来发请求fetch是浏览器后来提供的、更简单的新方式本质做的都是同一件事从浏览器向服务器发请求、拿数据。搞懂这些后下面就能理解为什么fetch的错误处理和你想的不太一样了。⬆ 返回目录2.2 常见误解有人会这样写try{constresawaitfetch(/api/user/list);constdataawaitres.json();returndata;}catch(e){console.error(请求失败,e);}这里有个关键点HTTP 4xx/5xx 并不会让fetch抛出异常只有网络失败、跨域等才会抛。所以404、500 等错误 → 不会被catch捕获网络断开、超时 → 会被捕获⬆ 返回目录2.3 正确做法要同时处理“网络/请求异常”和“HTTP 状态异常”asyncfunctionfetchUserList(){try{constresawaitfetch(/api/user/list);if(!res.ok){thrownewError(HTTP${res.status}:${res.statusText});}constdataawaitres.json();returndata;}catch(e){if(e.nameTypeErrore.message.includes(fetch)){console.error(网络异常请检查网络);}else{console.error(请求失败:,e.message);}throwe;// 让调用方也知道失败了}}要点res.ok判断 2xx否则手动throwres.json()可能抛 JSON 解析错误会被catch捕获网络类错误在catch里单独分支处理⬆ 返回目录三、JSON 解析错误最容易漏掉的一类3.1 常见场景后端返回的是字符串或者格式不对// 后端返回: 用户不存在纯字符串// 或者返回: {data: invalid}非法 JSONconstdataJSON.parse(response);// 直接崩JSON.parse抛的是SyntaxError如果不包一层try/catch会直接导致整段脚本报错甚至影响后续逻辑。⬆ 返回目录3.2 推荐写法functionsafeParse(str,fallbacknull){try{returnJSON.parse(str);}catch(e){console.warn(JSON 解析失败:,e.message,原始内容:,str?.slice(0,50));returnfallback;}}constdatasafeParse(response,{});思路解析失败时返回一个兜底值如{}或[]而不是让程序直接崩溃打warn方便排查问题把解析逻辑封装成safeParse减少重复代码⬆ 返回目录四、业务异常 vs 系统异常分类处理很多人把所有错误都当成“失败”来处理不做区分交互和排查都会受影响。4.1 业务异常可预期的“业务失败”比如余额不足、未登录、参数错误、权限不足等通常由后端通过 HTTP 状态码 业务码 消息返回需要展示给用户并做相应业务流程处理⬆ 返回目录4.2 系统异常程序/环境错误比如网络断开、服务器 500、JSON 解析失败、未捕获的运行时错误多半需要上报、告警用户只看到通用错误提示⬆ 返回目录4.3 实战示例asyncfunctionplaceOrder(orderData){try{constresawaitfetch(/api/order/create,{method:POST,body:JSON.stringify(orderData),});consttextawaitres.text();constdatasafeParse(text,null);if(!res.ok){// 业务异常有明确的业务码和提示if(data?.codeBALANCE_INSUFFICIENT){return{success:false,type:business,message:余额不足请先充值};}if(data?.codeUNAUTHORIZED){return{success:false,type:auth,message:请先登录};}// 其他 4xx/5xxreturn{success:false,type:system,message:data?.message||服务器异常请稍后重试};}return{success:true,data};}catch(e){// 系统异常网络错误、JSON 解析异常等reportError(e);// 上报监控return{success:false,type:system,message:网络异常请检查网络后重试};}}调用方可以这样区分constresultawaitplaceOrder(formData);if(result.success){// 跳转支付/成功页}elseif(result.typebusiness||result.typeauth){message.warning(result.message);// 业务提示用户可操作}else{message.error(result.message);// 系统异常建议稍后重试}⬆ 返回目录五、实战中的几条规范5.1 该用try/catch的地方JSON 解析JSON.parse、res.json()等容易抛错的地方可能抛出异常的第三方库如日期解析、复杂计算等同步的、可能出错的业务逻辑如参数校验、数据转换等⬆ 返回目录5.2 不要指望try/catch的地方异步回调用Promise的.catch、async/await的try/catch包住await那一行事件监听在回调里单独加try/catch全局错误用window.onerror或unhandledrejection做兜底⬆ 返回目录5.3 一个完整的小案例asyncfunctiongetProductDetail(id){try{constresawaitfetch(/api/product/${id});consttextawaitres.text();constdatasafeParse(text);if(!res.ok){if(data?.codeNOT_FOUND){return{ok:false,reason:product_not_found};}thrownewError(data?.message||请求失败:${res.status});}return{ok:true,data};}catch(e){if(e.nameSyntaxError){reportError(e,{context:JSON解析,id});return{ok:false,reason:parse_error};}if(e.message?.includes(fetch)||e.message?.includes(Network)){return{ok:false,reason:network_error};}throwe;}}⬆ 返回目录六、总结错误类型处理方式注意点Ajax网络错误try/catchres.ok判断4xx/5xx不会自动抛异常JSON解析错误对JSON.parse包try/catch建议封装safeParse业务异常根据code分支返回固定结构给用户明确提示系统异常catch后上报 通用提示避免暴露内部错误细节异步错误Promise .catch/async try不要指望外层同步try捕获记住不是所有错误都要用try/catch关键是区分“可预期业务失败”和“真正的异常”在合适的地方用合适的工具处理。⬆ 返回目录 本系列专栏导航 JS 基础语法与数据操作一、《var/let/const变量与作用域实战选型JS 基础语法与数据操作篇》二、《this、箭头函数与普通函数前端实战避坑指南 | JS 基础语法与数据操作篇》三、《对象解构赋值接口数据解包 10 个实战写法JS 基础语法与数据操作篇》四、《map/filter/reduce数组10个常用实战操作JS 基础语法与数据操作篇》五、《find/some/every/includes数组查找与判断实战用法JS 基础语法与数据操作篇》六、《sort/localeCompare对象数组排序与分组实战JS 基础语法与数据操作篇》七、《模板字符串 /split/join/ 正则字符串处理实战JS 基础语法与数据操作篇》八、《Date/dayjs日期时间处理实战JS 基础语法与数据操作篇》九、《try/catch/Promise前端错误处理实战JS 基础语法与数据操作篇》十、《import/export前端模块化实战JS 基础语法与数据操作篇》 跟着系列慢慢学把技术功底扎扎实实地打牢 更多内容TS/Vue/工程化等共47篇已整理成「全体系总目录」收藏后可一站式学习 系列总览想系统学习Vue3中后台开发收藏这份「全体系指南」47篇干货从基础到工程化全覆盖《前端基础实战JS/TS与Vue体系化扫盲47 篇完整目录 避坑》 每篇都配套实战场景避坑指南帮你摆脱「面向搜索引擎写代码」的尴尬⬆ 返回目录学习本就是一场持久战不需要急着一口吃成胖子。哪怕今天你只记住了一点点这都是实打实的进步。后续我还会继续用这种大白话、讲实战方式带大家扫盲更多前端基础。关注我不迷路咱们把那些曾经模糊的知识点一个个彻底搞清楚。如果你觉得这篇内容对你有帮助不妨点赞收藏下次写代码卡壳时拿出来翻一翻比搜引擎更靠谱。我是 Eugene你的电子学友我们下一篇干货见