如何在 Javascript 中重新抛出异常,但保留堆栈?

Posted

技术标签:

【中文标题】如何在 Javascript 中重新抛出异常,但保留堆栈?【英文标题】:How can I rethrow an exception in Javascript, but preserve the stack? 【发布时间】:2011-04-13 15:36:51 【问题描述】:

javascript 中,假设我想在发生异常时进行一些清理,但让异常继续向上传播,例如:

try 
  enterAwesomeMode();
  doRiskyStuff(); // might throw an exception
 catch (e) 
  leaveAwesomeMode();
  throw e;

doMoreStuff();
leaveAwesomeMode();

这段代码的问题是捕获并重新抛出异常会导致到该点的堆栈跟踪信息丢失,因此如果随后再次捕获异常,堆栈上的更高位置,堆栈跟踪只会向下到重新投掷。这很糟糕,因为这意味着它不包含实际引发异常的函数。

事实证明,try..finally 至少在 Chrome 中具有相同的行为(也就是说,问题并不是重新抛出,而是任何异常处理程序块的存在。)

有谁知道在 Javascript 中重新抛出异常但保留与之关联的堆栈跟踪的方法?如果做不到这一点,如何建议其他方法来添加异常安全的清理处理程序,同时在异常发生时捕获完整的堆栈跟踪?

感谢任何指点:)

【问题讨论】:

复制:***.com/questions/5249960/… 【参考方案1】:

如前所述,堆栈是在运行new Error(...) 时创建的快照,因此您不能真正使用同一个堆栈抛出错误。

我使用的一种解决方法是在抛出之前 console.error 堆栈:

  console.error(err.stack);
  throw err;

它并不完美,但它为您提供了足够的可调试信息,以及原始错误的堆栈。

【讨论】:

【参考方案2】:

Error 对象的 stack 属性是与 Error 对象本身同时创建的,而不是在它被抛出的时候。由于成语,它们通常是相同的

抛出新错误(“消息”);

如果你按照你写的代码来使用,当你重新抛出错误时,堆栈属性将不会改变。

【讨论】:

这不是真的(可能取决于平台)。我现在使用的 js 引擎(Rhino)在 throw 语句中重置堆栈,丢失原始堆栈。 也许是这样,但 rhino-1.7.7.2.jar 并没有改变它。你用的是什么版本?【参考方案3】:

这是 Chrome 中的一个错误。重新抛出异常应该保留调用跟踪。

http://code.google.com/p/chromium/issues/detail?id=60240

我不知道任何解决方法。

我没有看到 finally 的问题。在某些情况下,我确实看到异常在 finally 之后没有出现在错误控制台上,但似乎在开发版本中已修复。

【讨论】:

这个问题已经被关闭了。 Chrome 92 对我来说仍然是坏的。error.stack 反映了重新抛出的行号不是原始的

以上是关于如何在 Javascript 中重新抛出异常,但保留堆栈?的主要内容,如果未能解决你的问题,请参考以下文章

C#重新抛出异常:如何在IDE中获取异常堆栈?

抛出异常时如何获取 JavaScript 堆栈跟踪?

如何重新抛出异常

NSException:如何添加 userData 并重新抛出?

如何在 C# 中重新抛出 InnerException 而不会丢失堆栈跟踪?

如何在 SQL Server 中重新引发相同的异常