【问题标题】:How do I sleep every N iterations in a Javascript loop?如何在 Javascript 循环中每 N 次迭代休眠一次?
【发布时间】:2023-08-20 16:16:02
【问题描述】:

我目前有一个 Javascript forEach() 循环,但我需要更改我的代码以每 500 次迭代添加一个“睡眠”。

这种模式让我每次迭代都睡 3 秒:

How do I add a delay in a JavaScript loop?

for (let i=1; i<10; i++) {
    setTimeout( function timer(){
        alert("hello world");
    }, i*3000 );
}

如何在每 2 次或每 500 次迭代中睡觉?

PS:

解决方案需要在 Chrome 和 IE11 上运行。

【问题讨论】:

  • if ((i+1) % iterationCount === 0) { /* sleep */ }?
  • 当然,这不会阻止 for 循环继续执行 - 异步代码保持异步
  • 延迟使用Math.floor(i / 500) * 3000

标签: javascript


【解决方案1】:

递归超时解决方案:

const processInBatches = (array, limit, processFn, timeout) => {
    const batch = array.slice(0, limit);
    if(!batch.length) {
        return;
    }
    batch.forEach(processFn);
    const rest = array.slice(limit);
    setTimeout(() => processInBatches(rest, limit, processFn, timeout), timeout);
}

const array = ['a', 'b', 'c', 'd'];
processInBatches(array, 2, (x) => console.log('processing',x), 1000);

【讨论】:

  • 好点,虽然基于是否最终需要返回累积值的问题模棱两可
  • IE11 不支持简写函数定义。如果你打算使用转译器,那么也可以使用 async + promises。
【解决方案2】:

您可以创建一个函数来捕获闭包中的循环变量并返回一个简单的函数,该函数带有一个返回批量大小的循环。效果是它可以让你在你离开的地方继续 for 循环。如果你让它返回一个布尔值,指示它是否完成,你可以将整个事情包装在setInterval 中。显示比解释容易:

function batch(batch_size, end){
    var i = 0                                  // capture i in closure
    return function(){
        for(i; i <= end; i++){
            console.log("doing something", i)  // work goes here
            if (!((i+1) % batch_size)) return i++
        }
        return false
    }
}
var f = batch(5, 11)                           // 0 - 11 batched in groups of 5
if (f()){                                      // start immediately, then setInterval if not finished in one batch.
    var interval = setInterval(() => {
    f() ||  clearInterval(interval)
    }, 2000 )
}

【讨论】:

  • 我喜欢这个解决方案。我很好奇为什么缺少分号:( 完全披露:就个人而言,我是一个“总是使用大括号”的人......
  • @paulsm4 这是分号的风格问题。在大多数情况下不需要它们,我认为没有它们 JS 会更容易(也许这就是我的 python 教养)。不过,我不会去讨论它——总是使用它们有很好的论据。