Skip to content Skip to sidebar Skip to footer

Avoid Forced Delay Of Settimeout When Breaking Up Long Running Javascript Tasks

I have a long running task in JavaScript, which I break up in chunks with a series of nested setTimeout(processChunk, 0), similar to what is described here. However, for each invoc

Solution 1:

There is a straightforward workaround for this issue. Since the minimum delay of setTimeout is measured from when the timer is set, make sure to set timers at least 10–15 ms before each chunk should be processed. When several setTimeout are set, they queue up and the next one is invoked immediately after the previous, without the additional delay. This can be done with only 2 active timers:

functionrunLongTask() {
  var complete = false;
  functionprocessChunk() {
    if(!complete) {
      /* ... process chunk, set complete flag after last chunk ... *///set new timersetTimeout(processChunk);
    } else {
      /* ... code to run on completion ... */
    }
  }
  //set a timer to start processingsetTimeout(processChunk);
  //set an extra timer to make sure //there are always 2 active timers,//this removes the extra delay provided//that processing each chunk takes longer//than the forced delaysetTimeout(processChunk);
}

Below is a working demo comparing the workaround approach to the traditional approach of setting a new setTimeout after each chunk is processed. In the workaround there is always an extra setTimeout set ahead, reducing the processing time with about 4 ms or more for each chunk (about 40 ms or more for 10 chunks, as demonstrated below), provided that each chunk takes at least 4 ms to process. Note that the workaround demonstrates the use of only 2 active timers.

functionrunForAtLeast15ms() {
  var d = (+newDate) + 15;
  while(+newDate < d);
}

functiontestTimeout(repetitions, next, workaround) {
  var startTime = +newDate;

  functionrunner() {
    if(repetitions > 0) {
      //process chunkrunForAtLeast15ms();
      //set new timersetTimeout(runner);
    } elseif(repetitions === 0) {
      //report result to consoleconsole.log((workaround? 'Workaround' : 'Traditional') + 
                  ' approach: ' +
                  ((+newDate) - startTime) + ' ms');
      //invoke next() function if provided
      next && next();
    }
    repetitions--;
  }

  setTimeout(runner);

  if(workaround){
   //make sure that there are always 2//timers running by setting an extra timer//at startsetTimeout(runner);
  }
}

//First: repeat runForAtLeast15ms 10 times//with repeated setTimeouttestTimeout(10, function(){
  //Then: repeat runForAtLeast15ms 10 times//using a repeated set of 2 setTimeouttestTimeout(10, false, true);
});

Post a Comment for "Avoid Forced Delay Of Settimeout When Breaking Up Long Running Javascript Tasks"