hagino3000's blog

平成アーカイブス (更新停止)

JavaScriptの再帰処理の限界

JavaScript再帰処理をarguments.calleeを使って書くか、関数リテラル名指定で自分を呼び出すかでエラーになった時の挙動が違ったのでメモ。

arguments.calleeの場合

ブラウザ エラーになる回数 エラーメッセージ メモ
IE6 438 スタック領域が不足しています catchできない
IE7 1747 stack over flow at line XX. catchできない
window.onerrorでハンドルしようとするとIEがクラッシュ
Firefox 3.0 2999 too much recursion catchできない
Safari 4 Beta 40326 Maximum call stack size exceeded. catchできない

関数リテラル名指定の場合

ブラウザ エラーになる回数 エラーメッセージ メモ
IE6 462 スタック領域が不足しています catchできる
IE7 2495 スタック領域が不足しています catchできる
Firefox 3.0 2999 too much recursion catchできる
Safari 4 Beta 43686 Maximum call stack size exceeded. catchできる

検証コード

<html>
  <head>
    <title>Limit of Recursion</title>
    <script>
    var setup = function(){
      window.onerror = function(e, fileName, row){
        alert("catch失敗\nCount:"+ count + '\nMessage' + e);
      }
    }
    var count = 0;

    var test1 = function(){
      count = 0;

      var counter1 = function(){
        count++;
        arguments.callee();
      }

      (function(){
        try {
          counter1();
        } catch(e){
          alert('Count:' + count + '\nMessage:' + e.message);
        }
      })();
    }

    var test2 = function(){
      count = 0;
      var counter2 = function(){
        count++;
        counter2();
      }
      window.counter2 = counter2;

      (function(){
        try {
          counter2();
        } catch(e){
          alert('Count:' + count + '\nMessage:' + e.message);
        }
      })();
    }
    </script>
  </head>
  <body onload="setup()">
    Testing limit of recursion.<br />
    <input type="button" value="Recursion by arguments.callee" onclick="test1();" />
    <br />
    <br />
    <input type="button" value="Recursion by function name" onclick="test2();" />
  </body>
</html>


jsbinにテストページを作成しました
http://jsbin.com/ileju

まとめ

catchできないエラーが飛ぶのは困るので、再帰回数が1000を超える処理は注意が必要。しかしSafari 4つえーwww
ちなみに、あえて遅く実行したい処理はsetTimeout(arguments.callee, 0)で書いてます、これなら回数は気にしなくてもOK。