2

I'm working on a timer, and after some answers that I got in this forum it has all been working smoothly. This is what it looks like right now: (just so that you get the idea)

enter image description here

My code (please note that this is a work in progress so some stuff isn't quite finished; basically every function that has a alert("workin"); is still not being used.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>

<html>

<head>

<title>WIP</title>
<meta charset="UFT-8">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>


<script>

$(document).ready(function() {
 timerSet(9,12);
 timerRun();
});

function timerReset() {
 alert("workin");
}

function timerSet(inputMinutes, inputSeconds) {
 minutes = inputMinutes; 
 seconds = inputSeconds; 
 finalTimeInSeconds = minutes*60 + seconds; //finalTimeInSeconds is the time it takes for the timer to be 00:00 in seconds.
 timerPrint();
}

function timerAdd(inputMinutes, inputSeconds) {
 alert("workin");
}

function timerSubtract(inputMinutes, inputSeconds) {
 setTimeout(function () {
  if(minutes > 0 && seconds == 0) {
   minutes--;
   seconds = 59;
  } else {
   seconds--;
  }
  timerPrint();
 }, 1000);
}

function timerRun() {
 timerSubtract();
}

function timerStop() {
 alert("workin");
}

function timerPrint() {
 displayMinutes = (minutes.toString().length == 2) ? minutes : "0" + minutes; //ternary operator: adds a zero to the beggining 
 displaySeconds = (seconds.toString().length == 2) ? seconds : "0" + seconds; //of the number if it has only one caracter.
 $("#timerText").text(displayMinutes + ":" + displaySeconds);
}

function totalTime() {
 var totalTimeInSeconds = minutes*60 + seconds;

 return totalTimeInSeconds; //totalTimeInSeconds is the time that the timer now displays in seconds.
}

</script>

</head>

<body>

<div id="timerText">00:00</div>

</body>

</html>

So this is my problem: In the timerRun() function, I want the timerSubtract() function to repeat while totalTime() > 0, but the page just crashes if I use a while loop. Why does it do that? I don't think it's an infinit loop. What can I do to do want I want?

Thanks to whoever answers! :-)

cabralpinto
  • 1,814
  • 3
  • 13
  • 32
  • This looks like homework... – Maess Sep 08 '15 at 17:41
  • @Maess so what if it is... – Adam Buchanan Smith Sep 08 '15 at 17:42
  • 1
    Looking at how you want to add your while loop. The reason it will crash is because there is no `setTimeout` that will wait one second before calling `timerSubract()` what you do is you call `timerSubtract()` all the time without any pauses. Make sure your while-loop waits a moment before calling `timerSubtract()`. The logic how you use a while-loop fails, sadly. – AndersRehn Sep 08 '15 at 17:43
  • Why not using setInterval? http://jsfiddle.net/ouL1yzpq/ – Jonathan Anctil Sep 08 '15 at 17:43

4 Answers4

6

The problem is that timerSubtract does it's work using setTimeout.

Every time you use setTimeout you can imagine that it's setting aside that function for later. Then as soon as the program isn't doing anything (and if enough time has passed) then it runs the next function that was set aside. By running a while loop, you never give the runtime a chance to run your functions set aside using setTimeout.

One way of solving this while still using setTimeout would be to do something like this:

function timerRun() {
    if (minutes > 0 && seconds == 0) {
        minutes--;
        seconds = 59;
    } else {
        seconds--;
    }
    timerPrint();
    // Queue up timerRun to run again in 1 second
    setTimeout(timerRun, 1000);
}
timerRun();
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • How do I stop the timer?? And then resume it again? – cabralpinto Sep 08 '15 at 19:05
  • For examples of how to start and stop timers, I would suggest [checking the MDN page for setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout). – Mike Cluck Sep 08 '15 at 19:58
2

Instead of using setTimeout, why not use setInterval:

http://jsfiddle.net/ouL1yzpq/

setInterval(function () {
    if(minutes > 0 && seconds == 0) {
        minutes--;
        seconds = 59;
    } else {
        seconds--;
    }
    timerPrint();
}, 1000);

Check this to see how to stop timer: how to stop "setInterval"

Community
  • 1
  • 1
Jonathan Anctil
  • 1,025
  • 3
  • 20
  • 44
0

The timerSubtract function doesn't change the variables minutes or seconds. It only starts a timeout that would change the variables later on.

If you run the function in a loop waiting for the variables to change, then there will never be any changes to the variables. JavaScript is single threaded, so you have to exit out of the function and return the control to the browser for the timeouts to be executed. While the loop is running the timeout events will not be handled.

If JavaScript would have been multi threaded, then your loop would have started millions of timeouts until a second would have passed and the timeouts would start to execute. As you don't start a timeout once a second but as fast as possible, the timer would instantly count down to minus millions at that time.

Instead of starting a lot of timeouts, use a single setInterval in timerSubtract, and only call the function once. The interval will count down once a second, as I suspect that is how you want your timer to work:

function timerSubtract(inputMinutes, inputSeconds) {
    setInterval(function () {
        if(minutes > 0 && seconds == 0) {
            minutes--;
            seconds = 59;
        } else {
            seconds--;
        }
        timerPrint();
    }, 1000);
}

function timerRun() {
    timerSubtract();
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
0

As Jonathan posted, you can use setInterval. I would add clearInterval() to his answer to stop at 0 (is that what you want?) Like this:

function timerSubtract(inputMinutes, inputSeconds) {
    var countdown = setInterval(function () {
        if(minutes > 0 && seconds == 0) {
            minutes--;
            seconds = 59;
        } else {
            seconds--;
        }

        if( totalTime() <= 0){
            clearInterval(countdown);
            // timer is done, do something interesting..
        }

        timerPrint();
    }, 1000);
}

Also, over a long time the timer could be inaccurate. If you want better accuracy, read the actual current system time upon starting the timer, then at each interval, read the actual time again and subtract the two values (current - start) to get the actual elapsed time. Then subtract the elapsed time from the initial total to get the current time remaining.

Chaz
  • 319
  • 1
  • 6