结论:用 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,三个属性要一起看:
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 = 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 '用户名不能为空'(只是字符串,没堆栈,难调试)throw 的典型场景复杂项目还可自定义错误类,比如 class ValidationError extends Error,方便用 instanceof 精准识别。
最常被忽略的一点:try...catch 只捕获**当前执行上下文**的同步错误。Promise 的 reject、setTimeout 回调里的异常,它根本看不见——必须靠 await 把异步
“拉平”进同步流,才能进 catch。这点不理解,90% 的异步错误就漏抓了。