1

In this http://jsfiddle.net/kuox9ax2/ I have a timer that counts down.

  • When it reaches zero, it starts over. It shouldn't do that.
  • As JS is asynchronous I can't figure out how to get it to call a function only when it have reached zero.

I have tried to as return true in startTimer(), but then I run into that JS is asynchronous, so it returns true right away.

Can someone show how to solve these two issues?

function startTimer(duration, display) {
  var timer = duration, minutes, seconds;

  setInterval(function() {
    minutes = parseInt(timer / 60, 10)
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;

    display.textContent = minutes + ":" + seconds;

    if (--timer < 0) {
      timer = duration;
    }
  }, 1000);
}

window.onload = function() {
  var time = 5, display = document.querySelector('#time');
  var isDone = startTimer(time, display);

  if (isDone) {
    alert("a");
  }
};
<div>Timeout in <span id="time">00:00</span> minutes</div>
Shaohao
  • 3,471
  • 7
  • 26
  • 45
Jasmine Lognnes
  • 6,597
  • 9
  • 38
  • 58

3 Answers3

3

Store your interval in a variable and call clearInterval when reaching 0. Javascript functions can be passed as parameters, typically named callbacks. Simply pass a function as a parameter and call it when needed.

function startTimer(duration, display, callback) {
  var timer = duration,
    minutes, seconds;

  var myInterval = setInterval(function() {
    minutes = parseInt(timer / 60, 10)
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;

    display.textContent = minutes + ":" + seconds;

    if (--timer < 0) {
      timer = duration;
      
      // clear the interal
      clearInterval(myInterval);

      // use the callback
      if(callback) {
          callback();
      }
    }
  }, 1000);
}

window.onload = function() {
  var time = 5,
    display = document.querySelector('#time');
  startTimer(time, display, function() { alert('done'); });
};
<div>Timeout in <span id="time">00:00</span> minutes</div>
Jasmine Lognnes
  • 6,597
  • 9
  • 38
  • 58
Eric Herlitz
  • 25,354
  • 27
  • 113
  • 157
2

You can use WindowTimers.clearInterval()

function startTimer(duration, display) {
  var timer = duration, minutes, seconds;

  var myInterval = setInterval(function() {
    minutes = parseInt(timer / 60, 10)
    seconds = parseInt(timer % 60, 10);

    minutes = minutes < 10 ? "0" + minutes : minutes;
    seconds = seconds < 10 ? "0" + seconds : seconds;

    display.textContent = minutes + ":" + seconds;

    if (--timer < 0) {
      clearInterval(myInterval);
      doneFunction();
    }
  }, 1000);
}

window.onload = function() {
  var time = 5, display = document.querySelector('#time');
  startTimer(time, display);
};

function doneFunction(){
  console.log("done !");
}
<div>Timeout in <span id="time">00:00</span> minutes</div>
Weedoze
  • 13,683
  • 1
  • 33
  • 63
1

You cannot force an async method to return after the async operation completes - and to do so is an anti pattern.

Instead, you can pass a function to the method to be executed when the async operation finishes. You also need to store a reference to the setInterval() and call clearInterval() on that when the timer reaches zero. Try this:

function startTimer(duration, display, callback) {
  var timer = duration, minutes, seconds;

  var interval = setInterval(function() {
    var minutes = parseInt(timer / 60, 10)
    var seconds = parseInt(timer % 60, 10);

    display.textContent = ("00" + minutes).slice(-2) + ":" + ("00" + seconds).slice(-2);
    
    if (minutes === 0 && seconds === 0) {
      clearInterval(interval);
      callback && callback();
    }
    timer--;
  }, 1000);
}

window.onload = function() {
  var time = 5, display = document.querySelector('#time');
  
  startTimer(time, display, function() {
    console.log("timer reached zero");
  });
};
<div>Timeout in <span id="time">00:00</span> minutes</div>
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339