2012-01-16 77 views
0

我知道我遇到的問題是,我只是很難找到解決辦法。我想知道是否有人經歷過這樣的事情,他們實施了什麼樣的解決方案。運行setTimeout方法+傳遞變量的Javascript堆棧溢出

我有一個名單系統,等待維修,我想這是遲到閃爍黑色和紅色修理。這個列表中有很多修復可能很晚。

這裏是我的功能:

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做這個試試[this](http://jsfiddle.net/Krr7m/)。有關[MDN]的更多信息(https://developer.mozilla.org/en/CSS/CSS_animations)。您需要添加更多供應商特定的前綴才能使其適用於更多瀏覽器,並且不適用於舊版瀏覽器。 – 2012-01-16 18:21:26

+0

我不是每個元素的'setTimeout()'的忠實粉絲。使用列表,而不是:http://jsfiddle.net/HdCbt/ – 2012-01-16 18:48:32

+0

[超過最大調用堆棧大小]的Dup(http://stackoverflow.com/questions/8731840/),[爲什麼使用括號調用setTimeout不啓動新的callstack?](http://stackoverflow.com/questions/8058996/)。 – outis 2012-01-16 19:19:24

回答

3

您需要在setTimeout的從

setTimeout(setblink(id),500); 

更改爲:

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

setTimeout()預期的功能,如參數傳遞,而你傳遞函數的結果。

2

setblink(id)立即調用該函數。由於setTimeout計劃稍後執行,因此堆棧溢出是立即執行而非延遲執行的症狀,因此未來的調用不會被推送到當前調用堆棧上。

由於setblink需要一個參數,因此將其包裝在一個nullary匿名函數中,用於lazy evaluation

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,檢查是否有任何剩餘;如果沒有,則取消間隔。

(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(){}之內。