Javascript:使用Delay循环播放数组

Lov*_*ess 8 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
            );
        };

    },
Run Code Online (Sandbox Code Playgroud)

然而,它不起作用,我相信它可能是,因为"for"循环中的参数必须在setTimeout函数内.但我不知道如何使它发挥作用.

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

Jas*_*ant 11

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);
Run Code Online (Sandbox Code Playgroud)

小提琴演示


小智 8

您可能会想在这里使用递归函数而不是 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(); 
},
Run Code Online (Sandbox Code Playgroud)

或者,如果您确实更喜欢使用循环,您仍然可以这样做,但是需要做一些调整才能完成此操作。

首先,您需要将其放置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)
    );
  }

},
Run Code Online (Sandbox Code Playgroud)

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

但是,为了解释起见,我不想让您没有 for 循环版本;这些知识可以在其他地方派上用场。:)


Cur*_*urt 6

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

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);
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*ett 4

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

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ChrisBeckett请原谅挖一个旧的,但是我如何从函数外部停止loopThroughArray()?例如通过按钮? (2认同)