user1032531 user1032531 - 2 months ago 9
Javascript Question

Preserving variables in a function

I have a timer loop which I wish to perform one action ever three loops and then perform another action on the forth loop, and then repeat itself. I thought the following would work, but found that

counter
is not defined the next time
MyLoop()
is executed. It will be defined if I declare it in the global namespace, but then each loop will not have its own timer. How can I preserve the
counter
value within
MyLoop()
?

function MyLoop(t) {
console.log(counter);
if (typeof counter === 'undefined') {
var counter = 0;
}
setTimeout(function() {
if (counter >= 3) {
console.log('MAIN: Counter: ' + counter + ' Loop ' + t + ' seconds.')
counter = 0;
} else {
console.log('SUB: Counter: ' + counter + ' Loop ' + t + ' seconds.')
counter++
}
MyLoop(t);
}, t * 1000);
}

MyLoop(2);
MyLoop(4);

Answer

Very small sample that demonstrates the issue:

function S(condition) { 
  var v; 
  if (condition) {v  = 42;} 
}
S(true);
S(false); 

Do you expect v to be set to 42 on second call? Probably not, the same for your second call to MyLoop.

You are re-creating closure every iteration - instead re-use the same function you called first:

function MyLoop(t) {
  console.log(counter);
  if (typeof counter === 'undefined') {
    var counter = 0;
  }
  var onTick = function() {
    if (counter >= 3) {
      console.log('MAIN: Counter: ' + counter + ' Loop ' + t + ' seconds.')
      counter = 0;
    } else {
      console.log('SUB:  Counter: ' + counter + ' Loop ' + t + ' seconds.')
      counter++
    }
     setTimeout(onTick, t * 1000);
  };
  setTimeout(onTick, t * 1000);
}

Alternatively you can re-create function with correct counter:

function MyLoop(t, counter) {

 counter = counter || 0;

 setTimeout(function() {
    if (counter >= 3) {
      console.log('MAIN: Counter: ' + counter + ' Loop ' + t + ' seconds.')
      counter = 0;
    } else {
      console.log('SUB:  Counter: ' + counter + ' Loop ' + t + ' seconds.')
      counter++
    }
    MyLoop(t, counter); // creates new function with updated counter
  }, t * 1000);
}
Comments