Intervals are like timeouts that will reschedule themselves (which differs from a timeout starting a new timeout). Since intervals reschedule themselves, only create one. (Or, only as many as really necessary.)
The problem with the original post is it was creating 5 intervals (because they were being created in the loop) and then only keeping the interval ID (in counter) of the last interval created! Thus the clearInterval only stopped the last interval and the other 4 intervals kept running and running and running ..
Here is some cleaned up code with comments and without the original problem:
var count = 5;
// only need ONE interval
var counter = setInterval(timer, 1000);
// so we do one count RIGHT NOW
timer();
function timer() {
// display first, so we start at 5: 5, 4 .. 1
console.log(count);
count--;
if (count < 0) {
// to repeat the count, comment out the clearInterval
// and do `count = 5;` or similar .. take it from here :D
clearInterval(counter);
}
}
To create separate "state" for each countdown, either create a new countdown object that maintains state in properties or use a closure. Here is an example with a closure. I have also added support for a callback function to show how such a function can be made more generic:
function makeCountdown(startCount, delay, fn) {
fn = fn || function (i) {
// default action, if fn not specified
console.log(i);
};
// local variables
var count = startCount;
var counter = setInterval(timer, delay);
timer();
function timer() {
// now count and counter refer to variables in the closure (keyword!)
// which are different each time makeCountdown is called.
fn(count);
count--;
if (count < 0) {
clearInterval(counter);
}
}
}
makeCountdown(20, 500); // uses default function
makeCountdown(10, 1000, function (i) { console.log(10 - i) });
makeCountdown(5, 2000, function (i) { console.log("SLOW! " + i) });
Exercises:
- Add a callback function for when the countdown is "done" so that countdowns can be run in series.
- Consume a series generator and use that to generate the next
count value.
- Have
makeCountdown return an object that can be used to control the countdown.
- Have fun!