2016-08-31 6 views
0

私は再帰的なことを行う関数を実装しました。時には非同期に処理する必要があるため、ループを単純に使用することはできず、再帰的な関数呼び出しを使用する必要があります。非常に抽象的スニペットでInternalErrorを防ぎます:再帰が多すぎます

これは次のことを意味します:

function doStuff(){ 
    // async or sync things -> depends on several circumstances 
    doStuff(); 
} 
doStuff(); 

これは素晴らしい作品。しかし、あなたが予想しているように、これは、最大再帰呼び出し制限を超えたときに問題を引き起こします。場合によっては、25,000を超えるコールを処理する必要があります。最新のFirefox(50.0a2)でInternalError: too much recursionが発生します。

私はInternalErrorをキャッチし、タイムアウトしてコールバックを再トリガすることは働くことが判明しました:

function doStuff(){ 
    // async or sync things -> depends on several circumstances 
    try{ 
     doStuff(); 
    } catch(e if e instanceof InternalError){ 
     setTimeout(function(){ 
      doStuff(); 
     }.bind(this), 25); 
    } 
} 
doStuff(); 

しかし、これはハックと醜いです。したがって、私は、ループ内で何かを処理できず、再帰的な関数呼び出しを使用する必要があるときに、この状況を回避するための好ましい方法は何かを尋ねています。

+0

現在のブラウザでは、長いテールコールの削除が実装されていないため、ループを使用してください。ループは末尾再帰と同じように表現的であり、独自のスタックデータ構造を持つループは非末尾再帰と同じように表現的であることに注意してください。 'setTimeout'を利用しないでください。 – ftor

+0

1.なぜ 'setTimeout'を利用しないのですか?私はそれが醜いのは分かっていますが、これにはどんな機能的な欠点がありますか? 2.ある時点で非同期コードを実行する必要があるので、通常のループを使用することはできません。ループは実行を続けるでしょう... – dude

+0

'setTimeout'は非常に遅いです。しかし、私はあなたの疑似コードを理解していません。 'doStuff'は引数をとらず何も返しません。再帰的なケースはブロックしています。通常のループとまったく同じように動作します。ベースケースはどうですか? – ftor

答えて

1

コードを非同期に変換します。この場合、コールスタックは深くないでしょう

function doStuff(){ 
    setTimeout(doStuff, 0); 
} 
doStuff(); 
+0

はい、これも私が知ったことです(質問を参照)。しかし、これは悪い習慣ではありませんか?タイムアウトは常に私にとって警鐘です – dude

+0

非常に深い呼び出しスタックで再帰を使用する必要がある場合は、asycに変換するだけです。それもあなたのUIをブロックしません(しかし、私はその遅いと同期の例と思います)。サイクルを使用できないのはなぜですか? – Maxx

+0

申し訳ありません、ありがとうございます。より良いアプローチがないことを確認するために、数時間待ってみましょう。 – dude

関連する問題