user1032531 user1032531 - 3 months ago 13
Javascript Question

Nesting setIntervals loops

How should two setInterval loops be nested?

On the outer loop (setInterval1), I wish to make a server request every 4 seconds, and then in the inner joop (setInterval2), I wish to do something ever 1 second. After a few moments, my inner loop goes crazy, and if I attempt to clear it, it never triggers.

https://jsfiddle.net/y1f6nm6z/

var counter1 = 0;
var counter2 = 0;
var setInterval1 = setInterval(function() {
//$.getJSON( '/getData.php', function(json) {
console.log('counter1', counter1);
counter1++;
var setInterval2 = setInterval(function() {
console.log('counter2', counter2);
counter2++;
}, 1000);
//clearInterval(setInterval2);
//});
}, 4000);

Answer

Do not nest setIntervals (except if you clear them, maybe)

This is what happens when you do so:

setInterval1
     ├────> function1 ────> setInterval2
     │                           ├────> function2
     │                           ├────────> function2
     │                           ├────────────> function2
     │                           ⋮
     ├────────> function1 ────> setInterval2
     │                               ├────> function2
     │                               ├────────> function2
     │                               ├────────────> function2
     │                               ⋮
     ├────────────> function1 ────> setInterval2
     │                                   ├────> function2
     │                                   ├────────> function2
     │                                   ├────────────> function2
     │                                   ⋮
     ├────────────────>  …
     ⋮

I recommend setTimeout instead:

var counter1 = 0;
var counter2 = 0;
(function timeout1() {
  console.log('counter1', counter1);
  counter1++;
  var i = 0;
  (function timeout2() {
    console.log('counter2', counter2);
    counter2++;
    ++i;
    setTimeout(i < 4 ? timeout2 : timeout1, 1000);
  })();
})();

Even if you nest them, they are usually less problematic than setInterval. But use some conditional to make sure you only call setTimeout when necessary.

var counter1 = 0;
var counter2 = 0;
(function timeout1() {
  console.log('counter1', counter1);
  counter1++;
  var i = 0;
  (function timeout2() {
    console.log('counter2', counter2);
    counter2++;
    ++i;
    if(i < 4) setTimeout(timeout2, 1000);
  })();
  setTimeout(timeout1, 4000);
})();