37

I am trying to make a seconds countdown with Javascript.

Here is my HTML

<div id="ban_container" class="error center">Please wait
        <span id="ban_countdown" style="font-weight:bold">
        45</span>
        seconds before trying again
</div>

And my JS:

<script type="text/javascript">
    var seconds = <?php echo $user->getBlockExpiryRemaining(); ?>;

    function countdown(element) {
        var el = document.getElementById(element);

        if (seconds === 0) {
            document.getElementById("ban_container").innerHTML = "done";
            return;
        }
        else {
            el.innerHTML = seconds;
            seconds--;
            setTimeout(countdown(element), 1000);
        }
    }

    countdown('ban_countdown');
</script>

However for some reason, it is not waiting the timeout time, but instead executes countdown right away so that when I refresh the page it just displays "done" right away. I know it is actually being executed multiple times because if I do innerHTML += seconds + " "; it counts down from 45. Why is the timeout being bypassed?

Euan M
  • 1,126
  • 11
  • 20
Mike
  • 23,542
  • 14
  • 76
  • 87

3 Answers3

72

setTimeout(countdown(element), 1000); executes your function with that argument and passes the result into setTimeout. You don't want that.

Instead, execute an anonymous function that calls your function:

setTimeout(function() {
    countdown(el);  // You used `el`, not `element`?
}, 1000);
Euan M
  • 1,126
  • 11
  • 20
Blender
  • 289,723
  • 53
  • 439
  • 496
7

If you'd like to pass an argument to a function by setTimeout, try this:

setTimeout(countdown, 1000, element);

The syntax of setTimeout is the following:

setTimeout(function,milliseconds,param1,param2,...)
ddb
  • 2,423
  • 7
  • 28
  • 38
Doron Kimia
  • 77
  • 1
  • 2
  • Note: According to [Mozilla](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout), passing parameters like this only works for IE >= 10. – Mike Jul 29 '16 at 05:03
5

It is because setTimeout is asynchroneous. Try this:

setTimeout(function(){
   countdown('ban_countdown'); //or elemement
}, 1000);

This will make the function countdown execute after 1000 miliseconds.

Peter Rasmussen
  • 16,474
  • 7
  • 46
  • 63