打开网易新闻 查看精彩图片

凌晨3点,你的手机还在震。用户截图里一片白屏,控制台血红一片——这种场景,每个前端都经历过。

但多数人不知道:JavaScript自带的错误处理三件套(try/catch/finally),能把这种噩梦变成"用户无感知恢复"。问题是你真的用对了吗?

90%的崩溃,死于同一种错误

90%的崩溃,死于同一种错误

先认清敌人。JS错误分两类:语法错误(SyntaxError)在代码运行前就被拦截,而运行时错误(Runtime Error)才是线上杀手。

最经典的三种死法:

ReferenceError:直接调用未声明变量,像伸手进空口袋抓东西。

TypeError:给数字调字符串方法,好比让冰箱唱歌——对象根本没这功能。

RangeError:创建长度为-1的数组,数学上就不成立,程序直接掀桌。

打开网易新闻 查看精彩图片

这些错误不处理,执行流当场中断。用户看到白屏,你收到警报,所有人都不好过。

try/catch不是万能药,用错地方更糟

try/catch不是万能药,用错地方更糟

很多人把try/catch当护身符到处套,结果代码臃肿、性能损耗,还掩盖了真正该修的bug。

正确的打开方式:只包裹"可能失败且失败可接受"的操作。网络请求、用户输入解析、第三方API调用——这些属于"外部不可控",值得保护。

看个实战案例。fetch用户数据时,网络抖动、服务器500、JSON解析失败都可能发生:

async function fetchUserData(userId) { try { const response = await fetch(`/api/users/${userId}`); if (!response.ok) throw new Error("User not found"); const data = await response.json(); renderUserProfile(data); } catch (error) { console.error("Fetch failed:", error); displayFallbackUI("Couldn't load profile. Showing demo data instead."); } }

关键点在catch里的动作:不是默默吞掉错误,而是给用户可见的降级方案。demo数据、重试按钮、离线提示——让应用"带病运行"比直接死掉强十倍。

catch块还藏着一个调试神器:完整的错误对象包含堆栈追踪(stack trace)、错误信息、行号。线上环境配合日志上报,复现bug的速度从小时级降到分钟级。

打开网易新闻 查看精彩图片

finally:那个被80%的人遗忘的收尾者

finally:那个被80%的人遗忘的收尾者

finally的设计很朴素:无论try成功还是catch触发,这里的代码必定执行。像出门不管下不下雨,钥匙总要带。

典型场景是资源清理。加载动画要停、数据库连接要关、全局状态要复位——这些收尾动作如果散落在try和catch里,漏掉的概率极高。

但finally有个反直觉的坑:它自己抛出的错误会覆盖前面的错误。如果finally里写了个不靠谱的清理操作,原本要捕获的错误反而被吞掉,调试时你会怀疑人生。

另一个误区是在finally里return。这会强制覆盖try/catch的返回值,导致你以为返回了A,实际拿到的是B。这种bug隐蔽到能浪费你整个下午。

现代JS的错误处理,已经进化了

Promise时代带来了.catch()链式调用,async/await又让代码看起来像同步。但本质没变:错误处理是架构设计,不是语法糖。

一个趋势值得注意:可选链操作符(?.)和空值合并(??)减少了大量"防御性代码"。以前要try/catch防的属性访问,现在一行表达式搞定。但这不意味着try/catch过时——异步操作的错误边界, still 需要它兜底。

更激进的方案是错误边界(Error Boundary)模式,React里已经成熟。把UI组件包裹在错误边界中,子树崩溃不会拖垮整页。这和try/catch形成互补:前者保体验,后者保逻辑。

你的代码库里,有多少裸奔的fetch、没处理的JSON.parse、假设永远存在的DOM节点?下次发版前扫一遍,数字可能会让你坐不住。