资讯专栏INFORMATION COLUMN

JS的函数调用栈有多深?

AprilJ / 2198人阅读

摘要:中尾递归优化支持尾递归优化如果一个函数的最后一个操作是函数调用,那么将会用跳转而不是子调用。自从年双十一正式上线,累计处理了亿错误事件,付费客户有阳光保险核桃编程荔枝掌门对微脉青团社等众多知名企业。

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

原文: The maximum call stack size

译者: Fundebug

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

如果你写了一个一直调用自身的死循环,那么恭喜你,很快就可以看到报错: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);
    }

备注: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对1、微脉、青团社等众多知名企业。欢迎大家免费试用!

版权声明

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95755.html

相关文章

  • 一键生成属于自己QQ历史报告,看看你对自己QQ了解程度有多深?

    摘要:一键生成属于自己的历史报告,看看你对自己的了解程度有多深简介近几年,由于微信的流行,大部分人不再频繁使用,所以我们对于自己的数据并不是特别了解。这里要说明的是,加密函数的获取,需要具备一定的抓包基础才能获取得到。 [TOC] 一键生成属于自己的QQ历史报告,看看你对自己的QQ了解程度有多深? 简介 近几年,由于微信的流行,大部分人不再频繁使用QQ,所以我们对于自己的QQ数据并不是特别了...

    JinB 评论0 收藏0
  • 切图崽自我修养-使用模块化JS

    摘要:之前的闭包也好,自执行函数也好,都是模块化的一些尝试,直到规范推出之后,模块化才真正迅猛发展起来。因为有了模块化的概念,才有了按需加载的概念。 前言 我们来玩乐高积木吧 模块化Js已经成为了老生常谈,不过在JavaScript设计之初,由于定位的问题并没有提供类的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码。之前的闭包也好,自执行函数也好,都是模块化的一...

    littleGrow 评论0 收藏0
  • 切图崽自我修养-使用模块化JS

    摘要:之前的闭包也好,自执行函数也好,都是模块化的一些尝试,直到规范推出之后,模块化才真正迅猛发展起来。因为有了模块化的概念,才有了按需加载的概念。 前言 我们来玩乐高积木吧 模块化Js已经成为了老生常谈,不过在JavaScript设计之初,由于定位的问题并没有提供类的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码。之前的闭包也好,自执行函数也好,都是模块化的一...

    justjavac 评论0 收藏0
  • React 组件之间通讯

    摘要:父组件声明自己支持父组件提供一个函数,用来返回相应的对象子组件声明自己需要使用我胡汉三又回来了点击我如果是父组件向子组件单向通信,可以使用变量,如果子组件想向父组件通信,同样可以由父组件提供一个回调函数,供子组件调用,回传参数。 在使用 React 的过程中,不可避免的需要组件间进行消息传递(通信),组件间通信大体有下面几种情况: 父组件向子组件通信 子组件向父组件通信 跨级组件之间...

    dongxiawu 评论0 收藏0
  • ❤520,就用CSS给你她(他)送颗心❤

    showImg(https://segmentfault.com/img/bVbsRlD?w=211&h=184); 今天是520。一句温柔的问候,一束美丽的鲜花,一段真情的告白。但是作为一名与众不同的程序员,我们可不仅仅拥有上面的传情方法,别忘了每个人的手上可是都有其他人不具备的神奇技能,就是我们每天辛辛苦苦敲下的代码。 在这个特殊的日子,就用我们手中的魔法代码,来给你的她(他)制作出一个与众不...

    Donne 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<