循环 setTimeout 函数

Looping through setTimeout function

我正在尝试编写一个函数,通过 x 步(本例中的第 1 步、第 2 步)循环 x 次(本例中为 3 次)x 秒(本例中,第 1 步需要 2 秒,第 2 步需要 1 秒)。

所以我希望它循环如下:

第 1 步(2 秒) 第 2 步(1 秒) 第 1 步(2 秒) 第 2 步(1 秒) 第 1 步(2 秒) 第 2 步(1 秒)

我有下面的代码,但它只迭代了一次循环,我不明白为什么。

jQuery('input').click(function () {
    for(i = 0; i < 3; i++){
        jQuery('div').html('Step 1');
        setTimeout(function() { 
            jQuery('div').html('Step 2');
        },2000);
        setTimeout(function() { 
            jQuery('div').empty();
        },2000 + 1000);
    }
});

我希望循环以相同的时间继续,但在到达 .empty(); 后回到开头。

JSFiddle:http://jsfiddle.net/kmyjhgvd/

循环迭代 3 次,但超时始终相同:2000 和 3000,因此您创建了 3 个相同的回调,将在 2 秒内执行,另外 3 个回调将在 3 秒内调用。这里有你想要的,有 6 种不同的超时:

http://jsfiddle.net/nsg7ny7L/1/

jQuery('input').click(function () {
    var time=0;
    for(i = 0; i < 3; i++){
        setTimeout(function() { 
            jQuery('div').html('Step 1');
        },time++*1000);
        setTimeout(function() { 
            jQuery('div').html('Step 2');
        },time++*1000);
    }
    setTimeout(function() { 
        jQuery('div').empty();
    },time++*1000);
});

PS:确保你理解它是如何工作的:JS是单线程的,所以for循环连续调用setTimeout 6次......所有的开始时间几乎相同其中

现在您在没有超时的情况下直接在循环中执行第 1 步,因此第 1 步的所有三个事件将立即发生。然后你在超时中有第 2 步,但所有这三个都有相同的时间延迟,所以它们将在两秒后同时发生。你在不同的时间得到这个:

   0: Step 1 (i = 0)
   0: Step 1 (i = 1)
   0: Step 1 (i = 2)
2000: Step 2 (i = 0)
2000: Step 2 (i = 1)
2000: Step 2 (i = 2)
3000: empty (i = 0)
3000: empty (i = 1)
3000: empty (i = 2)

你会想要这个:

   0: Step 1 (i = 0)
2000: Step 2 (i = 0)
3000: Step 1 (i = 1)
5000: Step 2 (i = 1)
6000: Step 1 (i = 2)
8000: Step 2 (i = 2)
9000: empty

将第 1 步和第 2 步设置为超时,并设置时间延迟,使它们在彼此之后发生,即使用 i * 3000 作为偏移量。然后你可以在最后一步之后的单独超时中清空元素:

jQuery('input').click(function () {
  for(i = 0; i < 3; i++){
    setTimeout(function() { 
      jQuery('div').html('Step 1');
    }, i * 3000);
    setTimeout(function() { 
      jQuery('div').html('Step 2');
    }, i * 3000 + 2000);
  }
  setTimeout(function() { 
    jQuery('div').empty();
  }, 6000 + 3000);
});

递归方法答案:

function recursiveSteps(config) {
    var _step = config.step;
    config.step++;

    jQuery('div').html('Step 1');
    setTimeout(function() { 
        jQuery('div').html('Step 2');
    },2000);
    setTimeout(function() { 
        jQuery('div').empty();
        },3000);
    if(config.step < 3) setTimeout(function() {recursiveSteps(config);}, config.step*1000);
    //you could put an "end" step here if needed

}

jQuery('input').click(recursiveSteps);

我没有尝试过代码,但我认为这应该可行

jQuery('input').click(function () {
     loopAction (3, 1, 2); // x is number of loops - s1, s2 in seconds
});

function loopAction(x, s1, s2){
   If (x>0){                 // as long as x>0 start the iteration
      jQuery('div').html('Step 1');
      setTimeout(function() { 
          jQuery('div').html('Step 2');
          setTimeout(function() {
             loopAction(x-1, s1, s2); // recursive call to self
          }, s2*1000);
      },s1*1000);
  } else {
     jQuery('div').empty();    // x>0 is false
  }
}
jQuery('input').click(function () {

    var times = 0,
        printStep1 = function(){
            JQuery('div').html('Step 1');
            setTimeout( printStep2, 1000 );
        },
        printStep2 = function(){
            JQuery('div').html('Step 2');
            if( times++ < 3 ) setTimeout( printStep1, 1000 );
        };

    printStep1();
});

没有JQuery:

document.querySelector('input').addEventListener( "click", function () {

    var times = 0,
        printStep1 = function(){
            document.querySelector('div').innerHTML = 'Step 1';
            setTimeout( printStep2, 1000 );
        },
        printStep2 = function(){
            document.querySelector('div').innerHTML = 'Step 2';
            if( times++ < 3 ) setTimeout( printStep1, 1000 );
        };

    printStep1();
});

用超时连续执行一系列步骤的通用方法:

var steps = [
    {
        timeout: 2000,
        action: function() { jQuery('div').html('Step 1'); },
    },
    {
        timeout: 1000,
        action: function() { jQuery('div').html('Step 2'); },
    },
    {
        timeout: 1000,
        action: function() { jQuery('div').empty(); },
    }
];

function executeSteps(times, index) {
    index = index || 0;
    var task = steps[index];
    if(index > 0 || times > 0) {
        if(index == 0) times--;
        task.action();
        setTimeout(function() { 
            executeSteps(times, (index + 1) % steps.length);
        }, task.timeout);
    }
}

jQuery('input').click(function () { 
    executeSteps(3);
});

JSFiddle