setTimeout和数组

Kev*_*vin 11 javascript each settimeout underscore.js

我对使用setTimeout和每个迭代器感到困惑.如何重写以下内容,以便控制台在延迟5秒后输出每个名称?目前,以下代码在5秒后立即打印所有名称.我想要:

1)等待5秒,然后打印凯文
2)等待5秒,然后打印迈克
3)等待5秒,然后打印莎莉

var ary = ['kevin', 'mike', 'sally'];

_(ary).each(function(person){

  setTimeout(function(){
    console.log(person);
  }, 5000);    

});
Run Code Online (Sandbox Code Playgroud)

Lon*_*ler 13

您可以创建一个名为的变量offset,使计时器等待数组中的每个人多5秒,如下所示:

var ary = ['kevin', 'mike', 'sally'];

var offset = 0;
_(ary).each(function(person){

  setTimeout(function(){
    console.log(person);
  }, 5000 + offset);    
 offset += 5000;
});
Run Code Online (Sandbox Code Playgroud)


Kyl*_*Mit 11

您有三个基本选项:

  1. 对于Loop +setTimeout
    ...立即初始化每个人,但是根据索引位置错开开始时间,因此它们不会同时进行.
  2. setTimeout+条件递归
    ...每隔n秒检查一次- 我会告诉你是否需要做另一个
  3. setInterval+条件clearInterval
    ...每隔n秒保持运行- 直到我告诉你停止

这里有一个充实的例子:

1.对于Loop + setTimeout

关于这一个的几个笔记.这有点像开始接力赛,并提前向每个跑步者发出指令,准确地在5:00和5:02以及5:04开始,无论他们背后的人是很久以前完成还是没有'到了.

此外,您不能使用常规for i=0 loop,因为for运算符不定义新的函数范围.因此,在每个for循环中设置的对象值将适用于迭代.调用setTimeout时,它将仅使用最新值.所以我们需要一个闭包来存储每个循环中的值.我已经习惯了Array.prototype.forEach(),但是如果你想在jQuery或者Underscore中使用forEach实现,那也可以.

function ArrayPlusDelay(array, delegate, delay) {
 
  // initialize all calls right away
  array.forEach(function (el, i) {
    setTimeout(function() {
        // each loop, call passed in function
        delegate( array[i]);

      // stagger the timeout for each loop by the index
      }, i * delay);
  })
 
}

// call like this
ArrayPlusDelay(['a','b','c'], function(obj) {console.log(obj)},1000)
Run Code Online (Sandbox Code Playgroud)

2. setTimeout+条件递归

对于最后两个选项,我们正在制作自己的循环,因此我们必须自己跟踪索引,初始化为零并在整个过程中递增.

对于这个,我们将a)调用setTimeout将运行一次,b)在索引位置评估数组,c)检查数组中是否有更多元素,如果是,则从(a)开始.

   
function ArrayPlusDelay(array, delegate, delay) {
  var i = 0
  
  function loop() {
  	  // each loop, call passed in function
      delegate(array[i]);
      
      // increment, and if we're still here, call again
      if (i++ < array.length - 1)
          setTimeout(loop, delay); //recursive
  }

  // seed first call
  setTimeout(loop, delay);
}

// call like this
ArrayPlusDelay(['d','e','f'], function(obj) {console.log(obj)},1000)
Run Code Online (Sandbox Code Playgroud)

3. setInterval+有条件的clearInterval

注意:该函数setInterval将在调用后永久运行.初始设置时的返回值将提供间隔的参考值,因此它通常与功能组合clearInterval以可选地将其关闭

function ArrayPlusDelay(array, delegate, delay) {
  var i = 0
  
   // seed first call and store interval (to clear later)
  var interval = setInterval(function() {
    	// each loop, call passed in function
      delegate(array[i]);
      
        // increment, and if we're past array, clear interval
      if (i++ >= array.length - 1)
          clearInterval(interval);
  }, delay)
  
}

ArrayPlusDelay(['x','y','z'], function(obj) {console.log(obj)},1000)
Run Code Online (Sandbox Code Playgroud)


3*秘密第四选项(最好的一个)

选项1和2是有风险的,因为一旦您启动该列车,就无法在路上调用它(除了关闭浏览器).如果你的代表中有一个大型数组或一个重负载,如果你需要它可能会提供一些追索权.通过保存引用setInterval,我们可以不断访问迭代函数.我们只需要返回上面的interval对象并在调用我们的数组加延迟函数时保存它.

function ArrayPlusDelay(array, delegate, delay) {
  var i = 0
  
   // seed first call and store interval (to clear later)
  var interval = setInterval(function() {
    	// each loop, call passed in function
      delegate(array[i]);
      
        // increment, and if we're past array, clear interval
      if (i++ >= array.length - 1)
          clearInterval(interval);
  }, delay)
  
  return interval
}

var inter = ArrayPlusDelay(['x','y','z'], function(obj) {console.log(obj)},1000)
Run Code Online (Sandbox Code Playgroud)

然后,如果我们以后想要清除它,只需将其抛入控制台:

clearInterval(inter);
Run Code Online (Sandbox Code Playgroud)

jsFiddle中的所有3个演示

类似Stack Overflow问题:

  • #1 工作得很好。非常感谢您花时间对每个选项进行充分评论。 (2认同)

jAn*_*ndy 7

你可以做到

var ary = ['kevin', 'mike', 'sally'];

_(ary).each(function(person, index){

  setTimeout(function(){
    console.log(person);
  }, index * 5000);    
});
Run Code Online (Sandbox Code Playgroud)

在不增加timeout值的情况下,您可以setTimeouts使用完全相同的值初始化所有值(这就是您看到所见内容的原因).