如何捕获 "Maximum call stack size exceeded" 错误?

how to catch a "Maximum call stack size exceeded" error?

  try {
     requestAnimationFrame(function re(){
       re();
     })}
  catch (e){
       console.log(e);
     }

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

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

最终会触发错误,抛给 try 的不是动画的 id。我如何捕获这样的 "Maximum call stack size exceeded" 错误?

您正在 requestAnimationFrame() 函数内的函数 re() 中调用相同的函数。正确的做法是:

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

关于捕获最大堆栈大小超出错误的事情是我不确定它是如何工作的。浏览器唯一可以做的允许错误被捕获的事情是清空堆栈然后让下一个函数 运行 成为 catch 函数但是在那个时候(我认为浏览器甚至不能得到它far) 你不会知道你的代码在哪里出错,所以你尝试做的任何事情 运行 充其量都是严重的错误。

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

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

关于堆栈大小及其工作原理的详细描述可以在 this question

的答案中找到

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

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);
  }
});

这当然可以做到。不仅如此——如果你坚持一个有意义的模式,你可以确定在调用堆栈溢出之前你的函数有多少次 运行(我不敢在递归的函数上尝试它 invoked,而不是 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 中测试它。