【问题标题】:how to catch a "Maximum call stack size exceeded" error?如何捕获“超出最大调用堆栈大小”错误?
【发布时间】:2016-06-11 15:43:40
【问题描述】:
  try {
     requestAnimationFrame(function re(){
       re();
     })}
  catch (e){
       console.log(e);
     }

我在控制台中尝试了上面的代码,它没有按预期工作。在我看来,虽然

 requestAnimationFrame(function re(){
       re();
     })}

最终会触发一个错误,抛出到try 的是动画的id。如何捕获这样的“超出最大调用堆栈大小”错误?

【问题讨论】:

  • 这些错误通常来自无限循环对吧?
  • 你想通过使用requestAnimationFrame 来达到什么目的?
  • 另外关于捕获最大堆栈大小超出错误的事情是我不确定它是如何工作的。浏览器可以做的唯一一件事就是清空堆栈,然后运行下一个函数是 catch 函数,但在那时(我认为浏览器甚至不能做到那么远)你会没有迹象表明你的代码在哪里出错了,所以你尝试运行的任何东西充其量都是严重的错误。
  • 谢谢,这是我正在寻找的答案。
  • 好的,我会把它放在答案中

标签: javascript try-catch callstack


【解决方案1】:

最大调用堆栈大小超出错误可以像任何其他错误一样被捕获:

try {
  function recur() { recur(); };
  recur();
} catch (ex) {
  console.log("caught " + ex);
}

ECMAScript 规范中没有定义在这种情况下应该做什么(超出调用堆栈大小),但实际上,所有浏览器都会抛出可捕获的异常。然而,由于缺乏规范,不同的浏览器选择抛出不同类型的异常:我见过ErrorRangeErrorInternalError

您的代码中的问题与此无关。问题是您试图捕获调用requestAnimationFrame() 时发生的异常。但是您的 re() 函数此时不会运行,它会按照您的要求在下一帧中运行。在re() 内部,您可以将递归调用包装到re() 并在那里捕获堆栈溢出异常:

requestAnimationFrame(function re(){
  try {
    re();
  } catch (ex) {
    console.log("caught " + ex);
  }
});

【讨论】:

    【解决方案2】:

    关于捕获最大堆栈大小超出错误的问题是我不确定它是如何工作的。浏览器可以做的唯一一件事就是清空堆栈,然后运行下一个函数是 catch 函数,但在那时(我认为浏览器甚至不能做到那么远)你会没有迹象表明你的代码在哪里出错了,所以你尝试运行的任何东西充其量都是严重的错误。

    另一个问题(这可能是没有浏览器有此功能的原因)是因为您在错误后运行的大多数功能只会尝试以某种方式重新启动正常的 Web 功能。由于您不知道发生了什么故障,因此您无法阻止它再次发生,因此您最终会一次又一次地崩溃。这会使用户和浏览器都对您的网页感到愤怒。

    所以我想最好的办法是确保你的代码没有无限循环并且能够顺利运行

    可以在this question的回答中找到关于堆栈大小及其工作原理的详细说明

    【讨论】:

    【解决方案3】:

    您在requestAnimationFrame() 函数内部的函数re() 中调用相同的函数。正确的方法如下:

    function re(){
        //code here
        requestAnimationFrame(re); //loop back to start
    }
    

    【讨论】:

    • 谢谢。虽然这不是我的问题的答案,但它是我要问的问题的答案。
    • 我还想指出,这不是一个无限循环,他的代码是无限循环。以这种方式使用 requestAnimationFrame 将导致函数运行,直到某些原因导致它停止,但从技术上讲,它不是无限循环,因为 requestAnimationFrame 仅在浏览器准备好重绘 Dom 之前被调用,因此您不会像以前那样连续运行函数在他的问题中,您正在定期运行一个函数
    • 澄清一下,我只是在回答您问题的第二部分,我个人不知道您如何成功捕获最大调用堆栈大小错误。这里有一些信息on JavaScript Stack Sizes,还有一些关于计算它们大小的信息。
    【解决方案4】:

    这当然可以做到。不仅如此——如果你坚持一个有意义的模式,你可以确定你的函数在调用堆栈溢出之前运行了多少次(我不敢在递归调用的函数上尝试它 em>,而不是 returned,就像原来的问题一样,因为在这种情况下,调用堆栈会变得非常时髦):

    function doRecursionOrDieTryin(n = 0) {
        try {
        return doRecursionOrDieTryin(n + 1);
      } catch(err) {
        return `There was an exception: "${err}" when tryin' to make iteration no. ${n}`;
      }
    }
    
    doRecursionOrDieTryin()
    

    警告:这个函数会启动一个无限循环,所以如果你在遥远的将来尝试运行它可能会导致你的浏览器崩溃,届时常见的 JS 引擎将完全优化尾调用.对于 10/2018,它需要迭代编号。在 Chrome 69 中为 10454。在 Firefox 62 中,堆栈溢出的限制正在发生变化(从 10077 到 20989,然后是 22160),这可能是由于某种智能运行时优化。尚未在 Edge 中对其进行测试。

    【讨论】:

      猜你喜欢
      • 2013-07-08
      • 2018-01-01
      • 2019-08-04
      • 1970-01-01
      • 1970-01-01
      • 2011-08-31
      • 1970-01-01
      • 2012-08-15
      • 2018-01-24
      相关资源
      最近更新 更多