try-catch仅捕获同步运行时错误,无法捕获语法错误和异步错误;异步错误需用Promise.catch、await+try-catch、回调内try-catch或全局error/unhandledrejection监听;抛错应使用new Error()并补充name、stack及自定义属性。
JavaScript 中同步代码出错,try-catch 是唯一能拦截并处理的机制。它不会捕获语法错误(如 const a = ;),但能抓住运行时异常,比如 undefined.foo()、JSON.parse('invalid') 或手动抛出的 throw new Error()。
关键点:
catch 块接收一个参数(通常叫 error),它至少有 message 和 stack 属性error.message —— 丢掉调用栈就很难定位问题源头catch:try { riskyCall(); } catch (e) {} 这等于把错误吞掉,后续排查会非常被动if (error instanceof TypeError) 或检查 error.name
像 setTimeout、fetch、Promise 内部抛出的错误,写在 try 块里也捕获不到——因为执行时机已脱离当前调用栈。
正确做法分场景:
.catch() 或 await 配合 try-catch(注意 await 只对 Promise reject
ion 生效)try { const res = await fetch('/api'); if (!res.ok) throw new Error('HTTP error'); } catch (err) { console.error(err); }.catch() 会导致 UnhandledRejection,触发 window.addEventListener('unhandledrejection')
try-catch,或靠全局 window.onerror
这两个都是捕获全局错误的兜底手段,但覆盖范围不同:
window.onerror:捕获 JS 运行时错误、脚本加载失败(script.src 404)、以及部分资源加载错误(需配合 crossorigin)window.addEventListener('error'):主要捕获资源加载错误(、、),但**不捕获 JS 执行错误**unhandledrejection
error.stack 的完整信息(尤其跨域脚本),所以生产环境建议搭配 try-catch 主动上报关键路径手动抛错时,throw 'something went wrong' 看似简单,但会丢失关键上下文:
stack,无法知道在哪一行抛出name,难以分类(比如区分 ValidationError 和 NetworkError)throw new Error('Failed to parse user data'); 或自定义错误类:class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; } }err.field = 'email'; err.status = 400;
unhandledrejection 默认静默,不报错也不提示,等用户反馈才暴露问题。上线前务必加监听并上报。