Javascript:使用Delay循环播放数组

时间:2015-06-16 10:48:45

标签: javascript arrays

我试图遍历数组,但想要延迟输出数组的每个值。这就是我目前对它应该如何运作的理解:

修改

请求JS小提琴:http://jsfiddle.net/d3whkjww/

    loopThroughSplittedText: function(splittedText) {

        for (var i = 0; i < splittedText.length; i++) {
            // for each iteration console.log a word
            // and make a pause after it
            setTimeout(
                console.log(splittedText[i]),
                1000
            );
        };

    },

然而,它不起作用,我相信它可能是,因为&#34; for&#34;循环必须在setTimeout函数内。但我不知道如何让它发挥作用。

我得到的只是数组的每个值,但我希望它们出现延迟。我该怎么做?

13 个答案:

答案 0 :(得分:10)

var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];

function loopThroughSplittedText(splittedText) {
    for (var i = 0; i < splittedText.length; i++) {
        // for each iteration console.log a word
        // and make a pause after it
        (function (i) {
            setTimeout(function () {
                document.getElementById('text').innerHTML += splittedText[i];
                console.log(splittedText[i]);
            }, 1000 * i);
        })(i);
    };
}
loopThroughSplittedText(splittedText);

Fiddle Demo

答案 1 :(得分:3)

在我的示例中,它将向您展示如何在您停止之前有争议地遍历数组。这是为了让您了解如何延迟。它还会显示实际显示值的时间。

我会说你实际上可以从这个计时器创建一个很好的实用程序,并将它用于多种用途,并且使用它可以阻止你重复大块代码。

JavaScript循环示例:

var body = document.body;
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];

loopThroughArray(splittedText, function (arrayElement, loopTime) {
    body.innerHTML += arrayElement+ ": " + loopTime+ "<br/>";
}, 1000);

function loopThroughArray(array, callback, interval) {
    var newLoopTimer = new LoopTimer(function (time) {
        var element = array.shift();
        callback(element, time - start);
        array.push(element);
    }, interval);

    var start = newLoopTimer.start();
};

// Timer 
function LoopTimer(render, interval) {
    var timeout;
    var lastTime;

    this.start = startLoop;
    this.stop = stopLoop;

    // Start Loop
    function startLoop() {
        timeout = setTimeout(createLoop, 0);
        lastTime = Date.now();
        return lastTime;
    }
    
    // Stop Loop
    function stopLoop() {
        clearTimeout(timeout);
        return lastTime;
    }
    
    // The actual loop
    function createLoop() {
        var thisTime = Date.now();
        var loopTime = thisTime - lastTime;
        var delay = Math.max(interval - loopTime, 0);
        timeout = setTimeout(createLoop, delay);
        lastTime = thisTime + delay;
        render(thisTime);
    }
}

答案 2 :(得分:2)

代码的一个问题是i对所有回调都是通用的。因此,第一个回调被告知&#34;输出索引i&#34;的条目,但是当它执行初始循环时已经完成,所以i现在已经结束了文本。

实现您正在寻找的东西的一种方法是不使用for循环,而是使用(1)打印字符,(2)更新计数器/位置的函数,以及(3)如果需要,安排下一个角色:

loopThroughSplitText: function (text) {
    var i = 0;
    function printEntry() {
        console.log(text[i]);
        i++; // Increment the position
        if (i < text.length) { // If there are more chars, schedule another
            setTimeout(printEntry, 1000);
        }
    }
    printEntry(); // Print the first entry/char
}

答案 3 :(得分:2)

好的,因为它不是完全重复的,你需要增加循环中的延迟,也要逃避c losure variable in a loop issue

loopThroughSplittedText: function (splittedText) {
    splittedText.forEach(function (text, i) {
        setTimeout(function () {
            console.log(text);
        }, i * 1000)
    })
}

&#13;
&#13;
var obj = {
  loopThroughSplittedText: function(splittedText) {
    splittedText.forEach(function(text, i) {
      setTimeout(function() {
        document.getElementById('x').innerHTML += text
      }, i * 1000)
    })
  }
}

obj.loopThroughSplittedText('abcde'.split(''))
&#13;
<div id="x"></div>
&#13;
&#13;
&#13;

答案 4 :(得分:2)

递归函数调用可以完成这项工作:

var a = [
    1,2,3,4,5,6,7,8,9,10
    ];

function log(i){
    console.log(a[i]);
    if (i<a.length){
       setTimeout(function(){
           i++;
           log(i);
       },1000);
    }
}

log(0);

http://jsfiddle.net/Curt/rjve4whe/1/

答案 5 :(得分:1)

另一个解决方案,使用setInterval:

var i = 0;
var intv = setInterval(function() {
    if (i >= splittedText.length) {
        clearInterval(intv);
    } else {
        console.log(splittedText[i]);
        ++i;
    }
}, 1000);

答案 6 :(得分:1)

这里有几个问题

  1. setTimeout应该使用函数,而不是调用函数的结果
  2. setTimeout立即返回,所以你的循环中的所有动作都将在大致相同的时刻开始,所有动作都会在执行前等待1000ms(尽管有上述评论,这意味着它们都是在同一时间执行的)力矩)。
  3. 由于没有将循环控制变量包装在闭包中,i的值对于每次迭代都将等于splittedText.length
  4. 您需要做的是等待setTimeout指令执行,然后再继续循环的下一次迭代。

    例如:

    var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
    
    function loopThroughSplittedText(splittedText) {
        displayValue(splittedText,0);
    }
    
    function displayValue(arr, i){
        if(i<arr.length){
            setTimeout(function(){
                document.getElementById('text').innerHTML = arr[i];
                console.log(arr[i])
                displayValue(arr,i+1);
            },1000)
        }
    }
    
    loopThroughSplittedText(splittedText)
    

    实例:http://jsfiddle.net/d3whkjww/1/

答案 7 :(得分:1)

这也可行

 function loopThroughSplittedText(splittedText) {

        for (var i=0; i < splittedText.length;i++) {
            (function(ind, text) {
                setTimeout(function(){console.log(text);}, 1000 + (1000 * ind));
        })(i, splittedText[i]);
    }

 }

答案 8 :(得分:1)

提出问题的替代解决方案,即使用setTimeout的第三个参数,仅在较新的浏览器中支持

&#13;
&#13;
(function (splittedText) {
   for (var i = 0; i < splittedText.length; i++) {
      setTimeout(
         function(val) { console.log(val); },
         i * 1000,
         splittedText[i]
      );
   }
})(["Hello", "world", "!"]);
&#13;
&#13;
&#13;

API文档可以是seen here(请注意可选参数)。

答案 9 :(得分:1)

另一个样本:

var split = 'Lorem ipsum dolor'.split(' ');

var loop = function() {
  console.log(split[0]);
  split = split.slice(1);

  if (split.length > 0) {
    setTimeout(function() {
      loop();
    }, 1000);
  }
}

loop();

答案 10 :(得分:1)

你可能想要在这里使用递归函数而不是for循环。但是,我会解释这两种方式,以防万一你(或其他人读到这篇文章)你的心已经开始用循环来做这件事。

对于递归函数,一般的想法是你需要调用一次函数,然后让它自己重复调用,直到它完成了你想要它做的事情。在代码方面,它可能看起来像这样:

loopThroughSplittedText: function(splittedText) {

  // Create our counter; delayedOutput will use this to
  // track how far along in our string we are currently at
  var locationInString = 0;

  function delayedOutput() {

    // Output the next letter in our string
    console.log(splittedText[locationInString]);

    // Increment our counter so that on the next call we are on the next letter
    locationInString++;

    // Only perform setTimeout if we still have text left to output
    if (locationInString < splittedText.length) {

      // Functions can reference themselves using their own name
      setTimeout(delayedOutput, 1000);
    }
  }

  // Call our function once to get things started
  delayedOutput(); 
},

或者,如果你真的更喜欢使用一个循环,你仍然可以这样做,但是为了实现这个目的,还有一些必须要做的事情。

首先,您需要将console.log置于其自己的功能中。这是因为当你放置console.log(something)时,你实际上并没有传递它,而是当时正在那里调用,这不是你想要的;通过调用它,它会立即将文本吐出到控制台,而不是等到稍后。将它放在自己的函数中允许将它传递给setTimeout,以便稍后调用它。

其次,你将不得不在另一个函数中包含 函数,以确保它在激活时被赋予i的正确值。原因实际上是这样的:你的目的是告诉函数“当你准备好时,使用我设置你的时候i。”但是,你现在所做的就是有效地说“当你准备好了,看看i”。因为该函数在准备好触发之前不检查i是什么,所以直到你执行循环之后它才会知道它的值,这意味着i将是一个远高于你的数字想!

作为上述的一个子要点,您需要立即调用该函数。这称为立即调用的函数表达式。如果你不熟悉它们,那么它们肯定值得一试。它们的用途有点不寻常,但它们在正确的位置上是一个强大的工具。

最后,因为您现在正在设置所有内容,所以您需要确保每个函数的超时时间相隔一秒;就像现在一样,你说的是“从现在开始做所有这一切”,当你的意图是“从现在起一秒钟开始所有这一秒”。这个修复相对容易;你需要做的就是将你的超时时间乘以i,这样你就可以设置第一个从现在开始的1秒,第二个从现在起设置为2秒,依此类推。

所有这些组合为您提供了类似这样的代码:

loopThroughSplittedText: function(splittedText) {

  for (var i = 0; i < splittedText.length; i++) {
    setTimeout(
      (function(locationInString) {
        return function() {
          console.log(splittedText[locationInString]);
        };
      }(i)),
      (1000*i)
    );
  }

},

至于哪种解决方案更好,我可能会推荐递归函数。递归版本只会创建一个函数,为您传递的每个字符串调用自身,而for循环版本将为字符串中的每个字符创建一个函数,这可能会非常快速地失控。当您处理大型项目时,函数创建(以及一般的对象创建)在JavaScript中会变得昂贵,因此通常最好采用避免在可能的情况下创建大量函数的解决方案。

但是,为了便于解释,我不想在没有for循环版本的情况下离开你;这些知识可以在其他地方派上用场。 :)

答案 11 :(得分:1)

解决方案使用闭包 https://jsfiddle.net/x3azn/pan2oc9y/4/

function loopThroughSplittedText(splittedText) {
    var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
    for (var i = 0; i < splittedText.length; i++) {
        // for each iteration console.log a word
        // and make a pause after it
    (function(_i) {
        setTimeout(function() {
        window.document.getElementById('text').innerHTML = splittedText[_i];
        console.log(splittedText[_i]);
      }, 1000)
    }(i));

    }
}

loopThroughSplittedText()

答案 12 :(得分:0)

您可以通过3种方式实现

1. closure
2. Recursive
3. variable declaration using let

var data = ['a','b','c','d'];

关闭:

for(i=0; i<=data.length; i++) {
  (function(x) {
    setTimeout(() => {
       console.log(x);
    }, 1000)
  })(data[i]);
 }

让变量声明

for(const ind of data) {
 let local = ind;
 setTimeout(() => {
    console.log(local);
 }, 1000)
}