结论:用 try...catch 捕获同步错误,async/await + try...catch 才能捕获 Promise 异步拒绝;高风险操作如 JSON.parse()、嵌套属性访问、调用未定义方法必须加防护;catch 参数是标准 Error 对象,需关注 name、message、stack;finally 总执行但 return 会覆盖主流程返回值;throw 应用 new Error 主动抛错;try...catch 不捕获异步错误,须 await 拉平。

直接说结论:用 try...catch 捕获同步错误,async/await + try...catch 才能捕获 Promise 异步拒绝(reject),纯 .then().catch() 不能被外层 try 包住。
什么时候必须加 try...catch?
不是所有代码都要包,重点盯这三类高风险操作:
-
JSON.parse()—— 后端返回格式错、字段缺失、多一个逗号,立刻抛SyntaxError - 访问嵌套属性,比如
user.profile.address.city—— 中间任意一层是null或undefined就报TypeError - 调用可能未定义的方法,比如
someLib.init(),但库没加载成功或版本不兼容
这些地方不加防护,用户点一下就白屏,控制台堆栈还藏在深层异步里,很难定位。
catch 参数到底能拿到什么?
catch 后的参数(常写成 err 或 error)是个标准 Error 对象,别只读 err.message,三个属性要一起看:
立即学习“Java免费学习笔记(深入)”;
-
err.message:人类可读的提示,比如"Unexpected token '}'" -
err.name:错误类型名,如"SyntaxError"、"TypeError"、"ReferenceError"—— 这是做分支处理的依据 -
err.stack:完整调用栈,含文件名和行号,开发期调试必备,上线后可上报到监控系统
try {
JSON.parse('{"name": "Alice",');
} catch (err) {
console.error('类型:', err.name); // SyntaxError
console.error('信息:', err.message); // Unexpected end of JSON input
console.error('位置:', err.stack); // SyntaxError: ... at script.js:2:18
}
finally 不是摆设,但容易误用
finally 块一定会执行,哪怕 try 或 catch 里写了 return。它适合放「无论如何都得收尾」的逻辑:
- 关闭 loading 状态(比如把
loading = false放这儿,避免请求卡住导致 UI 一直转圈) - 清理定时器:
clearTimeout(timerId) - 还原表单按钮为可点击状态
⚠️ 注意:如果 finally 自己也写 return,它会覆盖 try 或 catch 的返回值 —— 这是很多人踩坑的地方。
function getData() {
try {
return 'success';
} catch (e) {
return 'error';
} finally {
return 'finally wins'; // 实际返回这个,前面两个都被忽略
}
}
throw 是主动控错的关键开关
别只等 JS 自动抛错。业务校验失败时,用 throw 主动中断,让 catch 统一兜底:
- 推荐写法:
throw new Error('用户名不能为空')(生成标准Error对象,带stack) - 避免写法:
throw '用户名不能为空'(只是字符串,没堆栈,难调试) -
表单提交前校验、API 响应数据结构合法性检查,都是
throw的典型场景
复杂项目还可自定义错误类,比如 class ValidationError extends Error,方便用 instanceof 精准识别。
最常被忽略的一点:try...catch 只捕获**当前执行上下文**的同步错误。Promise 的 reject、setTimeout 回调里的异常,它根本看不见——必须靠 await 把异步“拉平”进同步流,才能进 catch。这点不理解,90% 的异步错误就漏抓了。











