setTimeout和数组

时间:2013-06-22 00:50:38

标签: javascript underscore.js settimeout each

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

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

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

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

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

});

6 个答案:

答案 0 :(得分:10)

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

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

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

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

答案 1 :(得分:7)

您有三个基本选项:

  1. For Loop + setTimeout
    ...立即初始化所有人,但根据索引位置错开开始时间,这样他们就不会同时进行。
  2. setTimeout +条件递归
    ...每隔 n 秒检查一下 - 我会告诉你是否需要再做一次
  3. setInterval +条件clearInterval
    ...每隔 n 秒继续运行 - 直到我告诉你停止
  4. 在这里,每个人都充实了一个充实的例子:

    1。 For 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)
    
    
    

    2。 setTimeout +条件递归

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

    对于这个,我们a)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)
    &#13;
    &#13;
    &#13;

    3。 setInterval +条件clearInterval

    注意:函数setInterval将在调用后永久运行。它在初始设置时的返回值将提供对间隔的引用,因此它通常与函数clearInterval结合使用,以便可选地将其关闭在路上

    &#13;
    &#13;
    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)
    &#13;
    &#13;
    &#13;

    3 *秘密第四选项(最佳选择)

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

    &#13;
    &#13;
    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)
    &#13;
    &#13;
    &#13;

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

    clearInterval(inter);
    

    All 3 Demos in jsFiddle

    类似Stack Overflow问题:

答案 2 :(得分:6)

你可以做到

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

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

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

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

答案 3 :(得分:1)

对于立即发生的事情,

each通常会更好。

相反,如果您不介意更改数组,可以将其用作队列:

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

setTimeout(function loop() {
    console.log(ary.shift());

    if (ary.length)
        setTimeout(loop, 5000);
}, 5000);

将来会继续调用loop 5秒,直到队列中没有任何内容。

答案 4 :(得分:0)

array.forEach接受一个回调函数,这意味着它已经创建了一个新的函数范围,并且由于setTimeout的性质是非阻塞的,因此立即返回,您只需要为每次迭代增加回调函数执行的延迟即可。

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

ary.forEach(function(person, index){
    setTimeout(function(){
        console.log(person);
    }, 5000 * (index + 1));   
})

如果要在for循环中实现相同效果,可以使用IIFE或let关键字

IIFE示例:

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

for(var i = 1; i <= ary.length; i++){
    (function(i){
        setTimeout(function(){
            console.log(ary[i - 1]);
        }, 5000 * i); 
    })(i)
}

让关键字示例:[ECMAScript 6]

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

for(let i = 1; i <= ary.length; i++){
    setTimeout(function(){
        console.log(ary[i - 1]);
      }, 5000 * i); 
}

答案 5 :(得分:-1)

你可以使用setInterval()和一个简单的逐个计数器。

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

var i=0;
setInterval(function(){
    console.log(ary[i]);
    i++;
}, 5000);

但请注意,这将在我变为大于2之后开始抛出错误。您需要在那里进行某种验证,并确保清除间隔。