0

I am trying to run sequential countdown timers but can't figure out how to wait for the timer to finish before moving onto the next item.

for(var i = 0; i < 5; i++)
{
    var count = 5;
    var counter = setInterval(timer, 1000);
}

function timer()
{
    count--;
    if (count <= 0)
    {
        $('.workout-timer').text(count + "secs");
        clearInterval(counter);
        return;
    }

    $('.workout-timer').text(count + "secs");
}

This just goes into negative, however without the for loop the code counts down from 5 to 0 just fine. So my question is how would get several countdowns one after another? Is the timer not the right way to go about it?

12
  • Don't create 5 intervals. Create one (without a loop). Commented May 14, 2013 at 5:45
  • why not use setTimeout? Commented May 14, 2013 at 5:46
  • @user2246674 what does this mean? Commented May 14, 2013 at 5:47
  • @akonsu "why not use setTimeout?" <-- Justify, please. If I'm eating peanut butter, tell me why I should switch to jam. Commented May 14, 2013 at 5:48
  • the original poster wants to run timers in a succession and cancels them when the handler is called. this is what setTimeout is for. Commented May 14, 2013 at 5:50

2 Answers 2

1

You could do something like this:

function startCountdown(count, delay, callback) {
    if (!count) {
        callback && callback();
        return;
    }

    //do something here
    console.log(count);

    setTimeout(function () {
        startCountdown(--count, delay, callback);
    }, delay);
}

startCountdown(5, 1000, function () {
    startCountdown(5, 1500);
});

However this can get messy if you have a lot of nested callbacks, but here's one out of many approach you could use to deal with that issue:

var queue = [
        { count: 5, delay: 1000 },
        { count: 10, delay: 200 },
        { count: 5, delay: 5000 }
    ];

processNextCountdown();

function processNextCountdown() {
    var options = queue.shift();

    if (options) {
        startCountdown(options.count, options.delay, processNextCountdown);
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Why use a timeout over an interval?
because you do not have to cancel it.
@akonsu .. so? You only have to create one interval.
How would i get this to run sequentially? say 10 back to back countdowns?
I am to achieve multiple countdowns so: 5-4-3-2-1 then again 5-4-3-2-1
|
1

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:

  1. Add a callback function for when the countdown is "done" so that countdowns can be run in series.
  2. Consume a series generator and use that to generate the next count value.
  3. Have makeCountdown return an object that can be used to control the countdown.
  4. Have fun!

3 Comments

this doesn't address the issue I have, I am actually trying to get 5 separate countdowns that happen one after another
@user975044 Updated with an example that uses closures to remember the "count" and "counter" variables per interval.
@user975044 This can get as fun/complex/generic as needed. jQuery has a queue implementation for dealing with animations - e.g. move left 20, then fade out

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.