2011-11-09 42 views
1

我想是這樣的(新聞股票型功能):如何使用的setTimeout在爲...循環

  1. 從UL標籤
  2. 環獲得李的名單通過所有李時珍和獲取文本
  3. 顯示在通過火狐的console.log()
  4. 獲得下Li和重複,直到所有李時珍已經顯示

這是我們的目標控制檯文本,但setTimeout沒有運行,因爲我認爲它會。只顯示最後一次迭代(「後四次」)。那(「郵政四」)連續顯示四次。

<body> 
<ul id="post_list"> 
<li>Post One</li> 
<li>Post Two</li> 
<li>Post Three</li> 
<li>Post Four</li> 
</ul> 

<script type="text/javascript"> 
var ul = document.getElementById('post_list'); 
var li = ul.getElementsByTagName('li'); 

for(var x=0; x < li.length; x++){ 
    var li_text = li[x].childNodes[0].nodeValue; 
    setTimeout(function(){showText(li_text)}, 1000); 
} 

function showText(text) { 
    console.log(text); 
}   
</script> 
</body> 
+3

經典功能 - 在 - 一個循環的問題。這個問題一遍又一遍地被詢問...... –

+1

檢查右列的「相關」列表(與輸入問題標題時的列表基本相同,您看到了嗎?)。 – BalusC

+0

可能的重複[JavaScript關閉如何工作?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) –

回答

4

發生這種情況的原因是因爲關閉。 for循環塊已關閉,所以當您引用'li_text'時,它始終等於li_text設置爲的最後一個值。 for循環不爲通過循環爲每次迭代創建一個單獨的閉包。

+0

檢查到它。 – sleeper

+1

嗯..好像我偶然發現了一個大黃蜂巢!在回顧了答案之後,這是對什麼是錯誤**和爲什麼**的最好解釋。我對獲取代碼修復不感興趣,而是需要**理解**爲什麼我沒有得到正確的結果。在這種情況下,似乎答案是*閉包*。所以我即將去嘗試更清楚地理解這個問題。 – sleeper

+0

@Sleeper,如果你不希望超時是連續的,爲什麼你不創建一個超時,在超時後循環?不需要關閉和相同的功能。嘆。 :) – Esailija

0

更改此:

for(var x=0; x < li.length; x++){ 
    var li_text = li[x].childNodes[0].nodeValue; 
    setTimeout(function(){showText(li_text)}, 1000); 
} 

要:

for(var x=0; x < li.length; x++) (function() { 
    var li_text = li[x].childNodes[0].nodeValue; 
    setTimeout(function(){showText(li_text)}, x * 1000); 
})() 
+2

這是一個非常複雜的答案,一個治療症狀而不是問題的真實案例。 – GAgnew

0

怎麼樣,我們只是將一些張望了一下代碼...取出關閉問題...

var ul = document.getElementById('post_list'); 
var li = ul.getElementsByTagName('li'); 

for (var x = 0, xl = li.length; x < xl; x++) { 
    var li_text = li[x].innerText || li[x].textContent; // does IE support textContent?? 
    showText(li_text, x * 1000); 
} 

function showText(text, delay) { 
    setTimeout(function() { 
     console.log(text); 
    }, delay); 
} 

我假設你想要連續的延遲(因此循環)。因爲setTimeout沒有被阻塞,所以你需要在函數上有一個回調來調用下一個setTimeout,否則你需要用一個新的延遲專門增加每個函數調用。

+0

是你沒有緩存長度。你意識到「李」是生命的權利?並且'.length'很貴 – Raynos

+0

我不打算解決所有與代碼有關的問題......否則我只會用「YU NO USE DOM」來回答一半的jQuery問題 – rlemon

+0

沒有理由複製粘貼錯誤碼。你也可以使用'.childNodes'而不用過濾掉文本節點。 '.nodeValue'也不會做你認爲它做的事。我想你想'.textContent' – Raynos

2

格雷格提到的問題是關閉只評估一次。沒有人爲此發佈解決方案,所以這裏是一個。這使用添加生成的回調函數,每次一個函數:

地址:

function getShowTextCallback(text) { 
    return function(){showText(text)} 
} 

然後用它在循環這樣的:

for(var x=0; x < li.length; x++){ 
    var li_text = li[x].childNodes[0].nodeValue; 
    setTimeout(getShowTextCallback(li_text), 1000); 
}