You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中throw error与throw Error(error)的区别及选型建议

两种写法的核心区别

第一种写法

try {
  const result = await hello();
} catch (error) {
  throw error;
}

这种写法的行为是原样透传捕获到的原始错误:

  • 完整保留原始错误的所有信息:包括错误类型(比如TypeError、自定义业务错误类)、错误栈(直接指向报错的根源位置,比如hello()函数内部的出错行)、错误对象上挂载的所有自定义属性(比如业务错误码、请求详情等)。
  • 注意:这段try/catch本身是完全冗余的——你没有在catch块里做任何日志打印、状态回滚、错误补充操作,直接抛原错误和不写try/catch、直接写const result = await hello()的效果完全一致,属于没必要写的废代码。

第二种写法

try {
  const result = await hello();
} catch (error) {
  throw Error(error);
}

这种写法是创建了一个全新的通用Error对象抛出,会直接破坏原始错误的信息链路:

  • 丢失原始错误类型:不管原始错误是类型错误、参数错误还是自定义的业务错误,抛出后全变成最普通的Error实例,上层靠instanceof判断错误类型的逻辑会全部失效。
  • 丢失原始错误栈:新Error的调用栈会从当前throw的位置开始记录,原始错误里指向hello()内部出错位置的栈信息会被覆盖,排查问题的时候根本找不到最初的报错点。
  • 丢失所有自定义属性:原始错误上挂的业务码、接口返回的错误详情、请求路径等附加信息,在新的Error对象上全部不存在。
  • 唯一保留的只有原始错误的message文本,会被拼到新Error的message里,信息损失非常严重。
第二种写法是否有必要?

99%的场景下完全没有必要,属于典型的错误实践。
它没有给错误增加任何有用的上下文信息,纯粹是把原始错误的有效信息抹掉了一层,不管是上层逻辑处理错误,还是开发排查问题,都会被这种写法坑到。
如果确实需要包裹错误、补充当前层级的上下文(比如标注这个错误是在「拉取用户信息」「提交订单」这类具体业务步骤中抛出的),应该使用ES2022标准支持的cause参数来保留原始错误链路,写法如下:

try {
  const result = await hello();
} catch (error) {
  // 补充当前步骤的上下文信息,同时保留原始错误
  throw new Error("调用hello方法执行用户初始化操作失败", { cause: error });
}

这种写法下,原始错误会被完整挂载在新错误的cause字段上,错误栈也能通过cause追溯到根源,上层需要访问原始错误信息的时候也能正常取到,是合理的错误包裹方式。

实际开发的推荐写法
  • 如果你不需要在错误捕获后做任何额外操作(打日志、回滚loading状态、补充业务上下文等),不要写多余的try/catch,直接const result = await hello()即可,让错误自然向上抛到统一的错误处理层即可,多写一层空catch除了增加冗余代码没有任何意义。
  • 如果你需要在catch块做处理后再抛出错误:
    • 不需要补充上下文就直接用throw error,保证原始错误信息完整透传。
    • 需要补充业务上下文就用带cause参数的错误包裹写法,不要用throw Error(error)这种丢信息的写法。
  • 任何场景下都不推荐写throw Error(error),这种写法百害无一利。

内容的提问来源于stack exchange,提问作者cam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 01:49:15