【问题标题】:Javascript recursive loop over array with setTimeout?带有setTimeout的数组上的Javascript递归循环?
【发布时间】:2017-03-03 04:33:57
【问题描述】:

我在 ES6 中有这段代码:

function loopLettersEvery3Seconds() {
    const letters = ['a', 'b', 'c'];

    let offset = 0;
    letters.forEach((letter, index) => {
      setTimeout(() => {
        // I do something with the letter, nothing important
      }, 3000 + offset);
      offset += 3000;
      if (index === letters.length - 1) {
        loopLettersEvery3Seconds(letters);
      }
    });
}

这个函数循环遍历一个字母数组,每 3 秒我可以对每个字母做一些事情。但问题是,当这个循环结束并完成时,我不能再重复这个过程......递归调用会产生堆栈溢出(Uncaught RangeError: Maximum call stack size exceeded)lol

告诉我怎么做!谢谢!!

BR

【问题讨论】:

    标签: javascript arrays recursion


    【解决方案1】:

    你可以做这样的事情。这就是您可以通过递归和 setTimeouts 模拟 setInterval 的方式

    var array = ['a', 'b', 'c']
    
    function loopLettersEvery3Seconds(arr, index) {
        if (index === arr.length) return;
        //Do stuff with array
        setTimeout(loopLettersEvery3Seconds, 3000, arr, index+1)
    }
    loopLettersEvery3Seconds(array, 0)
    

    这样,您不必处理循环的同步性质,而是根据调用堆栈和 Web api 做所有事情(这是超时的正确术语吗?)

    如果你想让它永远循环,那么就这样做

    var array = ['a', 'b', 'c']
    
    function loopLettersEvery3Seconds(arr, index) {
        if (index === arr.length) return loopLettersEvery3Seconds(arr, 0);
    
        setTimeout(loopLettersEvery3Seconds, 3000, arr, index+1)
    }
    loopLettersEvery3Seconds(array, 0)
    

    【讨论】:

    【解决方案2】:

    forEach 是同步的。您在设置最后一个超时后立即进行递归调用,这显然会导致当函数在没有基本情况停止的情况下调用自身时导致堆栈溢出。

    对于永远运行的动画,您需要将“递归”调用放入最后一次超时:

    function loopLettersEvery3Seconds() {
      ['a', 'b', 'c'].forEach((letter, index) => {
        setTimeout(() => {
          // I do something with the letter, nothing important
          if (index === letters.length - 1) {
            loopLettersEvery3Seconds(letters);
          }
        }, 3000 * (index + 1));
      });
    }
    

    【讨论】:

      【解决方案3】:

      您可能应该使用setInterval 而不是setTimeout,这样可以避免使用offset 变量。请注意,您可以使用取模 (%) 运算符来确保您的索引在递增时“循环”:

      function loopLettersEvery3Seconds() {
          const letters = ['a', 'b', 'c']
          let index = 0
          
          setInterval(() => {
            console.log(letters[index])
            index = (index + 1) % letters.length
          }, 3000)
      }
      
      loopLettersEvery3Seconds()

      【讨论】:

      • @SeanKwon OP 并不真的希望它停止它的出现
      • @Bergi Woops,说得太早了。
      • @Bergi 添加无限循环功能
      • 你能解释一下(详细地)模(余数)运算符在这里是如何工作的吗?另见:stackoverflow.com/a/50339293/2153622
      • (index + 1) % letters.length 这里和(index + 1) < letters.length ? (index + 1) : 0做同样的事情
      【解决方案4】:

      我想在这种情况下最好使用准递归循环;

      var chars = ["a","b","c"];
      
      function loop(a,i = 0){
        console.log(a[i%a.length]);
        setTimeout(loop,1000,a,++i);
      }
      
      loop(chars);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-15
        • 2013-01-30
        • 2012-01-31
        • 1970-01-01
        • 2011-07-05
        • 1970-01-01
        • 2011-12-31
        • 1970-01-01
        相关资源
        最近更新 更多