2012-01-16 13 views
0

私は経験している問題が何であるか知っています。誰かがこのようなことを体験したのか、彼らがどのような解決策をとったのか、私は疑問に思っていました。Javascriptスタックオーバーフロー、setTimeoutメソッド+渡し変数

私は保留中の修理のリストシステムを持っており、黒と赤の点滅が遅い修理が必要です。このリストには複数の修理が遅れている可能性があります。ここ

は私の関数である。

function setblink(id) { 
    var elm = document.getElementById(id); 
    if (elm.color == "red"){ 
     elm.color = "black"; 
    } 
    else{ 
     elm.color = "red"; 
    } 
    setTimeout(setblink(id),500); 
} 

私は「IDの」repsToBlink呼ば点滅する必要がある項目についての配列を持っています。

次のコードを実行することによって、これらの修復ごとに設定された点滅間隔が実行され、再帰的なループになります。

for(var x in repsToBlink){ 
setTimeout(setblink(repsToBlink[x]),500); 
} 

スタックオーバーフローを起こすことなく、同じコードを実行するにはどうすればよいですか?

ありがとうございます!

+1

純粋なCSSでこれを行う場合は、[こちら](http://jsfiddle.net/Krr7m/)を試してください。詳細は[MDN](https://developer.mozilla.org/ja/CSS/CSS_animations)をご覧ください。より多くのブラウザで動作するようにベンダー固有のプレフィックスを追加する必要があり、古いブラウザでは動作しません。 –

+0

私は、各要素の 'setTimeout()'の大ファンではありません。リストを代わりに使用する:http://jsfiddle.net/HdCbt/ –

+0

[Maximum Call Stack Size Exceeded](http://stackoverflow.com/questions/8731840/)、[なぜかっこ付きのsetTimeoutを起動しないと新しいコールスタック?](http://stackoverflow.com/questions/8058996/)。 – outis

答えて

3

:あなたは、関数の結果を渡しているのに対し、

setTimeout(function() { setblink(id) },500); 

setTimeout()は、関数がパラメータとして渡されることを期待しています。

2

setblink(id)はすぐに関数を呼び出します。スタックオーバフローは、遅い実行ではなく、即時実行の症状であり、setTimeoutは後で実行されるようにスケジュールされているため、将来の呼び出しは現在の呼び出しスタックにプッシュされません。

setblinkには引数がありますので、lazy evaluationの匿名機能nullaryで囲みます。

function setblink(id) { 
    var elm = document.getElementById(id); 
    if (elm.color == "red"){ 
     elm.color = "black"; 
    } 
    else{ 
     elm.color = "red"; 
    } 
    setTimeout(function() {setblink(id)},500); 
} 

for (var x in repsToBlink){ 
    (function (id) { 
     setTimeout(function() {setblink(id)},500); 
    })(repsToBlink[x]); 
} 

このコードでは、さらに改善が求められています。

repsToBlinkが配列である場合、あなたべきrepsToBlinkfor (...;...;...))のloop over the integer indices、ない性質(for ... in)。しかし、代わりにIDを持つオブジェクトを(値ではなく)インデックスとして使用する場合は、for ... inが適切です。

上記はそれぞれid(ブラウザを圧倒する可能性があります)の別のタイマーを起動します。ループをスケジューリングされる唯一の機能となる機能に移すことにより、単一のタイマーが必要とされる。

定期的に機能を実行しているので、setIntervalが適切です。

repsToBlinkからIDを削除するときは、残っているかどうかを確認してください。そうでない場合は、間隔をキャンセルします。あなたがに

setTimeout(setblink(id),500); 

からあなたのsetTimeoutを変更する必要が

(function() { 
    var repsToBlink, repCount=0, blinkInterval; 

    function startBlinking(ids) { 
     addRepsToBlink(ids); 
     if (! blinkInterval) { 
      blinkInterval = setTimeout(blinkAll, 500); 
     } 
    } 

    function addRepsToBlink(ids) { 
     for (var i=0; i<ids.length; ++i) { 
      addRep(ids[i]); 
     } 
    } 

    function addRep(id) { 
     if (! id in repsToBlink) { 
      ++repCount; 
      repsToBlink[ids[i]] = true; 
     } 
    } 

    function removeRep(id) { 
     if (id in repsToBlink) { 
      delete repsToBlink[id]; 
      --repCount; 
      if (!repCount) { 
       clearInterval(blinkInterval); 
       blinkInterval=0; 
      } 
     } 
    } 

    function blinkAll() { 
     for (id in repsToBlink) { 
      blink(id); 
     } 
    } 

    function blink(id) { 
     var elm = document.getElementById(id); 
     if (elm.color == "red"){ 
      elm.color = "black"; 
     } else { 
      elm.color = "red"; 
     } 
    } 

    window.startBlinking = startBlinking; 
    window.addRepsToBlink = addRepsToBlink; 
    window.addRep = addRep; 
    window.removeRep = removeRep; 
})(); 
1

問題は、setTimeoutがグローバルコンテキストで呼び出されていることです。それで、あなたは即座にその関数を呼び出しています。それは、このコードを取得します

通訳、:

setTimeout(setblink(id),500);

は、その関数の戻り値はタイムアウトが呼び出すことになっているものであると仮定すると、すぐにsetblink関数を呼び出しています。これは再帰関数であるため、スタックオーバーフローが発生します。

これを修正するには、setTimeoutが呼び出す関数をfunction(){}にラップします。

関連する問題