JS的函数调用栈stack size的计算方法
如果你写了一个一直调用自身的死循环,那么恭喜你,很快就可以看到报错:UncaughtRangeError:Maximumcallstacksizeexceeded。那么这个callstacksize有多少呢?
1.计算方法
如下的方法可以为你计算出你使用的JavaScript引擎可以支持多深的调用(由BenAlman的一段代码获得灵感):
functioncomputeMaxCallStackSize(){ try{ return1+computeMaxCallStackSize(); }catch(e){ //Callstackoverflow return1; } }
运行得到如下三个结果:
- Node.js:11034
- Firefox:50994
- Chrome:10402
这些数字代表了什么呢?Mr.Aleph告诉我在V8,可调用的层数基于两个方面:1.栈的大小;2.每一栈帧的大小(用于记录函数参数和局部变量)。你可以在computeMaxCallStackSize声明局部变量来测试,你会发现数字变小。
2.ECMAScript6中尾递归优化
ECMAScript6支持尾递归优化:如果一个函数的最后一个操作是函数调用,那么将会用“跳转”而不是“子调用”。也就是说如果你将computeMaxCallStackSize重写成如下形式,在ES6的严格模式下,就会一直运行了。
functioncomputeMaxCallStackSize(size){ size=size||1; returncomputeMaxCallStackSize(size+1); }
3.亮点评论
Andrei:“ECMAScript6”版本的代码根本跑不通。虽然size会被更改,但是最终并没有值返回。
回复Andrei:有趣!你不能用这段代码去计算stacksize。在ES6下,这段代码会一直运行,因此不会返回数据。在其它情况下,会返回RangeError。为了使其工作,我把代码重写了一下:
varcomputeMaxCallStackSize=(function(){ returnfunction(){ varsize=0; functioncs(){ try{ size++; returncs(); }catch(e){ returnsize+1; } } returncs(); }; }());