JS的函数调用栈有多深?

译者按: 有时候会遇到Maximum call stack size exceeded的问题,本文教你stack size的计算方法。html

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

若是你写了一个一直调用自身的死循环,那么恭喜你,很快就能够看到报错:Uncaught RangeError: Maximum call stack size exceeded。那么这个call stack size有多少呢?git

1. 计算方法

以下的方法能够为你计算出你使用的JavaScript引擎能够支持多深的调用(由Ben Alman的一段代码得到灵感):github

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

备注:justjavac提到因为尾递归优化会致使堆栈报错信息不许确而逐渐不被支持,请你们移步评论区了解详情。微信

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

关于Fundebug

Fundebug专一于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对一、微脉、青团社等众多知名企业。欢迎你们免费试用函数

版权声明

转载时请注明做者Fundebug以及本文地址:
https://blog.fundebug.com/2018/06/15/call-stack-size/学习

相关文章
相关标签/搜索