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/學習

相關文章
相關標籤/搜索