setTimeout里面的for循环&范围解决问题

时间:2012-06-14 16:14:29

标签: javascript scope window sencha-touch settimeout

  

可能重复:
  How to Use setTimeout in a for…loop
  calling setTimeout with a for loop

对我来说,setTimeout函数在for循环中不起作用。它会在所有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控制台日志语句中获得相同的值?

3 个答案:

答案 0 :(得分:2)

这不完全是由于闭包,这是因为javascript是单线程的,并且设置Timeout不会发生,直到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/

答案 1 :(得分: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();

答案 2 :(得分: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();