4

I currently have a Javascript forEach() loop, but I need change my code to add a "sleep" every 500th iteration.

This pattern lets me sleep for 3 seconds every iteration:

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 );
}

How can I sleep for every 2nd - or every 500th - iteration?

PS:

The solution needs to run on Chrome and IE11.

paulsm4
  • 114,292
  • 17
  • 138
  • 190

2 Answers2

4

A recursive timeout solution:

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);
Andy Ray
  • 30,372
  • 14
  • 101
  • 138
  • good point, although ambiguous based on the question if a cumulative value needs to be returned eventually – Andy Ray Sep 02 '18 at 01:46
  • IE11 does not support shorthand function definition though. If you are going to use a transpiler, well then use async + promises as well. – mpm Sep 02 '18 at 01:51
2

You could create a function that captures a looping variable in a closure and returns a simple function with a loop that returns on batch sizes. The effect is that it lets you continues the for loop where you left off. If you have it return a boolean indicating whether or not it's done you can wrap the whole thing in a setInterval. Easier to show than explain:

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 )
}
Mark
  • 90,562
  • 7
  • 108
  • 148
  • I like the solution. I'm curious why the lack of semicolons :( Full Disclosure: Personally, I'm an "always use braces" kind of guy... – paulsm4 Sep 02 '18 at 04:13
  • @paulsm4 it's a matter of style on the semicolons. They aren't needed in most situations and I think JS is easier on the eyes without them (maybe that's my python upbringing). I wouldn't go to the mat on it though — there are good arguments for always using them. – Mark Sep 02 '18 at 04:42