2012-06-14 50 views
1

可能重複:
How to Use setTimeout in a for…loop
calling setTimeout with a for loop的setTimeout在for循環和範圍的決議問題

對於我來說,setTimeout功能不會在for循環工作。執行完循環語句後執行。

我正面臨着這個範圍問題的情況下在javascript中的setTimeout函數。

這裏是我的代碼片段..

... moves[] is an array .. 

for(i=0;i<noOfMoves;i++) { 

     playerName = moves[i].playerName; 
     timeDiff = moves[i].timeDiff; 
     console.log("Inside for loop"+ playerName); 

     setTimeout(function(){ 
      console.log("Inside set time out :"+playerName); 
     },timeDiff); 
.... 
.... 
} 

但它笨拙打印出下面的輸出...

Inside for loopplayer1 
Inside for loopplayer2 
Inside for loopplayer3 
Inside for loopplayer4 
.... (noOfMoeves times ..) 
Inside set time outplayer1 
Inside set time outplayer1 
Inside set time outplayer1 
Inside set time outplayer1 

編輯:的

我想O/P以下方式

我期待打印「Inside for loop」控制檯日誌首先,然後等待「timeDiff」期間,然後打印「Inside settimeout」功能控制檯日誌..我怎麼能做到這一點? -

Inside for loopplayer1 
Inside set time outplayer1 // (after waiting for timeDiff time) 
Inside for loopplayer2 
Inside set time outplayer2 // (after waiting for timeDiff time) 
...... 
...... 

另外,playerName變量在每個settimeout控制檯日誌語句中獲得相同的值嗎?

+2

常見的關閉問題。有人會發現這個笨蛋比我快。 :) – epascarello

+1

令人驚訝的是,當人們搜索時可以找到什麼。我的查詢是[for循環中的javascript settimeout](http://stackoverflow.com/search?q=javascript+settimeout+in+for+loop)。第一個結果。 – 2012-06-14 16:21:56

+0

@user:你確定你的輸出是*「Inside set time ** outplayer1 **」*,而不是*「Inside set time ** outplayer4 **」*? – 2012-06-14 16:29:59

回答

1

這是因爲關閉。改變你的代碼是這樣的:

for(i=0;i<noOfMoves;i++) { 
    playerName = moves[i].playerName; 
    console.log("Inside for loop"+ playerName); 
    (function(name) { 
     setTimeout(function(){ 
      console.log("Inside set time out :"+name); 
     },timeDiff); 
    })(playerName); 
} 

您可以瞭解更多關於關閉here

更新代碼:

var moves = [ 
    {playerName: '1'}, 
    {playerName: '2'}, 
    {playerName: '3'}, 
    {playerName: '4'} 
]; 
var timeDiff = 1000; 
var currentMove = 0; 

var processNextMove = function() { 
    var move = moves[currentMove]; 
    console.log('Inside for loop: ' + move.playerName); 
    currentMove++; 
    window.setTimeout(function() { 
     console.log('Inside set time out: ' + move.playerName); 
     if(currentMove != moves.length) { 
      processNextMove(); 
     } 
    }, timeDiff); 
}; 

processNextMove(); 
+0

您的代碼遭遇OP所具有的相同問題。 – tjscience

+1

你是不對的。請測試這個代碼http://jsfiddle.net/JuM4Z/ – KAdot

+0

我想在settimeout控制檯日誌中使用相同的playerName值..同時..我希望它的順序發生每個for語句..即執行「Inside for loop」,然後「Inside set time out」'noOfMoves' times – user1452041

2

這並不完全是由於工廠倒閉,這是由於這樣的事實,JavaScript是單線程的,並設置超時將不會發生,直到JavaScript有空閒時間來執行。 for循環將始終在setTimeout執行代碼之前完成。

爲了解決這個問題,把一切都變成的setInterval像這樣:

var moves = [{playerName:'Test'},{playerName:'Terry'}, {playerName:'sdfsdf'}]; 
var currIdx = 0; 
var intervalId = window.setInterval(function() { 
    var playerName = moves[currIdx].playerName; 
    console.log("Inside for loop"+ playerName); 
    (function(name) { 
     setTimeout(function(){ 
      console.log("Inside set time out :"+name); 
     },0); 
    })(playerName); 
    currIdx++; 
    if(currIdx >= moves.length) 
     window.clearTimeout(intervalId);   
}, 10); 

請參閱搗鼓一個樣本 - http://jsfiddle.net/uTyVw/2/

+0

它與封閉有關。傳遞給'setTimeout'的每個函數都關閉了同一個'playerName'變量。解決方法是在每次迭代中創建一個新的變量作用域,並使'setTimeout'函數在該作用域中的局部變量上創建一個閉包。 – 2012-06-14 16:32:25

+1

你錯過了這一點。不管是否關閉,在for循環完成之前,setTimeout都不會執行。 – tjscience

+0

這是爲什麼?如果這不是所需的行爲,那麼沒有理由首先使用'setTimeout'。 – 2012-06-14 16:37:38

0

它看起來像你想一步到下一個項目一旦迭代和延遲完成。這是一個可以幫助你的步進器。

// Generic stepper. On step will move to next item and 
// run custom stepping function. If at the end will return 0. 
function Stepper(stepfunc, items) { 
    this.items = items; 
    this.index = -1; 
    this.stepfunc = stepfunc; 
} 

Stepper.prototype.start = function() { 
    this.index = -1; 
    this.step(); 
} 

Stepper.prototype.step = function() { 
    this.index++; // move to the next item 

    // Stop when we reach the end. 
    if (this.items.length <= this.index) { 
     return 0; 
    } 

     /* Do something now. */ 
     var item = this.items[this.index]; 
     this.stepfunc(item); 

     return 1; 
} 

// Custom step function. 
function myStep(item) { 
    // Do this now. 
    console.log(item.n); 

    // Get a reference to the stepper. 
    var s = this; 

    // Do this later. 
    setTimeout(function(){ 
     console.log(item.n + ' after ' + item.t); 
     var status = s.step(); 
     console.log(status); 
    }, item.t); 
} 

var items = [{n: 'A', t: 500}, {n: 'B', t: 600}, {n: 'C', t: 1000}]; 
var s = new Stepper(myStep, items); 
s.start();