javascript如何抛出错误_try_catch如何使用【教程】

JavaScript中throw应统一用new Error()以保留堆栈,try...catch仅捕获同步错误,异步需在回调或await中处理;catch不可空,须分类处理、记录并决定是否重抛。

JavaScript 中抛出错误和使用 try...catch 不是为了“写得更规范”,而是为了在特定条件下中断执行、传递问题上下文、避免整个脚本崩溃——尤其是异步操作、用户输入、外部数据解析等场景。

如何用 throw 主动抛出错误

抛错不是只有 throw new Error() 一种写法,但其他形式容易埋坑:

  • throw 后面可以是任意值(字符串、数字、对象),但只有 Error 实例自带 stack 和标准属性,调试时才可定位到抛出处
  • 浏览器控制台对非 Error 类型的报错不显示堆栈,比如 throw "network failed" 只会打印字符串,没行号没调用链
  • 推荐统一用 throw new Error("message");如果需携带额外字段(如错误码),可继承 Error 或直接挂载属性:const err = new Error("timeout"); err.code = "ETIMEDOUT"; throw err;

try...catch 捕获什么、不捕获什么

try...catch 只能捕获同步代码中抛出的错误,对以下情况完全无效:

  • 异步回调里的错误(如 setTimeout(() => { throw new Error() }))——必须在回调内部加 try...catch,或用 .catch() 处理 Promise
  • 事件处理器中的错误(如 button.addEventListener('click', () => { throw ... }))——同样需在 handler 内部包裹
  • 语法错误(ParseError)和引用未声明变量(ReferenceError)在代码加载/执行前就报错,try...catch 进不去
  • Promise 拒绝(reject)不会触发 catch 块,除非你用 await 且没加 .catch()

catch 块里该做什么、不该做什么

捕获错误后,重点不是“吞掉它”,而是判断是否能恢复、是否要上报、是否要降级处理:

  • 不要空 catchcatch(e) {} 是最常见隐患,错误静默丢失,后续逻辑可能因状态异常而错上加错
  • 区分错误类型再处理:比如 e instanceof TypeError 可能是参数错,e.message.includes("timeout") 可能要重试,e.code === "ECONNREFUSED" 则提示服务不可用
  • 捕获后通常要记录(console.error(e) 或发给监控系统),再决定是否 throw e 继续向上抛,或返回默认值(如 return [])让调用方继续运行
  • 注意 catch 不能捕获 finally 里新抛的错误——

    如果 finally 里有 throw,它会覆盖原错误

try...catch 在 Promise 和 async/await 中怎么用

async 函数内部的 try...catch 能捕获 await 的 Promise 拒绝,但仅限于当前函数作用域:

  • async function f() { try { await Promise.reject("oops") } catch(e) { console.log(e) } } —— ✅ 正常捕获
  • async function f() { try { someAsync().then(() => { throw "oops" }) } catch(e) { } } —— ❌ then 回调是新执行上下文,catch 捕不到
  • 多个 await 连续调用时,一个失败会跳过后续 await,但不会自动跳过 catch 后面的同步代码
  • 想并行执行多个 Promise 并分别处理错误?用 Promise.allSettled(),而不是靠 try...catch 包一层

真正难的不是语法,是判断哪一层该抛、哪一层该捕、哪一层该忽略——多数线上静默失败,都源于在不该吞错误的地方加了空 catch,或在该提前校验的地方依赖了 catch 善后。