欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解JS函数stack size计算方法

程序员文章站 2024-01-21 20:16:22
为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。 如果你写了一个一直调用自身的死循环,那么恭喜你,很快就可以看到报错:uncaught...

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

如果你写了一个一直调用自身的死循环,那么恭喜你,很快就可以看到报错:uncaught rangeerror: maximum call stack size exceeded。那么这个call stack size有多少呢?

1. 计算方法

如下的方法可以为你计算出你使用的javascript引擎可以支持多深的调用(由ben alman的一段代码获得灵感):

function computemaxcallstacksize() {
    try {
      return 1 + computemaxcallstacksize();
    } catch (e) {
      // call stack overflow
      return 1;
    }
  }

运行得到如下三个结果:

  • node.js: 11034
  • firefox: 50994
  • chrome: 10402

这些数字代表了什么呢?mr.aleph告诉我在v8,可调用的层数基于两个方面:1. 栈的大小;2. 每一栈帧的大小(用于记录函数参数和局部变量)。你可以在computemaxcallstacksize声明局部变量来测试,你会发现数字变小。

2. ecmascript 6中尾递归优化

ecmascript 6支持尾递归优化:如果一个函数的最后一个操作是函数调用,那么将会用“跳转”而不是“子调用”。也就是说如果你将computemaxcallstacksize重写成如下形式,在es6的严格模式下,就会一直运行了。

function computemaxcallstacksize(size) {
    size = size || 1;
    return computemaxcallstacksize(size + 1);
  }

3. 亮点评论

  • andrei: “ecmascript 6”版本的代码根本跑不通。虽然size会被更改,但是最终并没有值返回。
  • 回复andrei: 有趣!你不能用这段代码去计算stack size。在es6下,这段代码会一直运行,因此不会返回数据。在其它情况下,会返回rangeerror。为了使其工作,我把代码重写了一下:
var computemaxcallstacksize = (function() {
 return function() {
  var size = 0;
  function cs() {
   try {
    size++;
    return cs();
   } catch(e) {
    return size + 1;
   }
  }
  return cs();
 };
}());