First program: javascript countdown timer

Viewed 976

I'm trying to code my own timer from scratch. Complete noob here. I know there's a good amount of tutorials out there about building a timer, but from experience, whenever I use examples I don't really learn. Here's the code I come up with:

<p id="myTimer">Blank Text</p>

var timer = 60;

function updatePLEASE() {
    timer--;
}

while (timer > 0){
    console.log(timer);
    document.getElementById("myTimer").innerHTML = timer;
    setTimeout(updatePLEASE(), 1000); /* replicate wait 1 second */
}

When it runs, it shows "1". I thought it was returning a boolean value at first until I added the console.log and saw that the script does thankfully countdown from 60 down to 1. But, the script seems to only use setTimeout once.

Why doesn't the script wait 1000 ms before running the loop again? Or better question: Am I using the setTimeout function correctly?

4 Answers

setTimeout take function name and it will if not while and change the text within function.

var timer = 60;

function updatePLEASE() {
    timer--;
    if (timer > 0){
    //console.log(timer);
    document.getElementById("myTimer").innerHTML = timer;
    setTimeout(updatePLEASE, 1000); /* replicate wait 1 second */
}
}
updatePLEASE();
<p id="myTimer">Blank Text</p>

setTimeout is async. Therefor you need something that will wait for that async operation to end.

You can do it in 2 ways:

1. wrap it with a "recursive" function.

So after 1 sec you call this function again and again until 0.

let timer = 60;

function updatePLEASE() {
  timer--;
}

function countDownTimer() {
  if (timer > 0) {
    console.log(timer);
    document.getElementById("myTimer").innerHTML = timer;
    updatePLEASE();
    setTimeout(countDownTimer, 1000); /* replicate wait 1 second */
  }
}

countDownTimer();
<p id="myTimer">Blank Text</p>

2. Use await and Promise:

let timer = 60;

function updatePLEASE() {
  timer--;
}

async function countDownTimer() {
  while (timer > 0) {
    console.log(timer);
    document.getElementById("myTimer").innerHTML = timer;
    await new Promise(resolve =>
      setTimeout(() => {
        updatePLEASE();
        resolve();
      }, 1000));

  }
}

countDownTimer();
<p id="myTimer">Blank Text</p>

You have two problems with the code:

1) The while loop completes before any setTimeout is run. Just so you know: setTimeout is asynchronous. Maybe you should do some reading about sync vs async code in Javascript.

2) The first param of setTimeout is a function. You pass the result of the function.

setTimeout accept function name only or variable function, however by mistake u exciting it.

setTimeout(updatePLEASE(), 1000);

Correct:

setTimeout(updatePLEASE, 1000);

Note: Code is wrong. it will run while loop without the wait of setTimeout. Because setTimeout runs asynchronously in event-loop.

More: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

You can delay using async-await. but example is little complex. I will recommend use recursion for this case.

var timer = 60;
const delay = (fn) =>
  new Promise((r) => {
    fn();
    setTimeout(r, 1000);
  });
function updatePLEASE() {
  timer--;
}
async function main() {
  while (timer > 0) {
    // delay 1 sec
    console.log(timer)
    await delay(updatePLEASE);
  }
}
main();

Related