I want to create a simple countdown timer for 10 minutes. I have figured out how to do this for the most part but with setInterval() it seems to stop with 2 seconds left every time. I have heard that setInterval() can be very unreliable but I don't know what else to do.
I set the timer to 1 minute and the seconds reset to 3 instead of 59 for time-saving purposes with running the code.
const value = document.querySelector("#time"); const startBtn = document.querySelector("#btn-start") const resetBtn = document.querySelector("#btn-reset"); startBtn.addEventListener('click', function(){ var minute = 1; var sec = 3; setInterval(function(){ value.innerHTML = minute + ":" + sec; sec--; if(sec < 0){ minute--; sec = 3; } if(sec <=9){ sec = "0" + sec; } if(sec == 0 && minute == 0){ alert("DONE!"); location.reload(); } }, 1000); }); resetBtn.addEventListener('click', function(){ location.reload(); })#main{ position: relative; display: flex; justify-content: center; align-items: center; padding: 20px; height: 100%; } .container{ position: relative; margin-top: 5%; } #title{ display: block; font-family: 'Roboto', sans-serif; font-size: 50px; font-weight: 600; color:rgba(0, 0, 0, 0.83); margin: 20px auto; padding: 0; } #time{ display: block; font-family: 'Roboto', sans-serif; font-size: 70px; text-align: center; margin: 20px auto 50px auto; } .function-buttons{ position: relative; display: flex; flex-direction: row; justify-content: center; align-items: center; } .reset-btn{ display: block; font-family: 'Roboto', sans-serif; font-size: 25px; width: 150px; background: #eee; margin: 0 10px; padding: 10px 30px; text-align: center; border-radius: 5px; border: none; outline: none; transition: .4s ease-in-out; cursor: pointer; } .reset-btn:hover{ background: red; color: #fff; } .start-btn{ display: block; font-family: 'Roboto', sans-serif; font-size: 25px; width: 150px; background: #eee; margin: 0 10px; padding: 10px 30px; text-align: center; border-radius: 5px; border: none; outline: none; transition: .4s ease-in-out; cursor: pointer; } .start-btn:hover{ background: #0096ff; color: #fff; }<!DOCTYPE html> <html> <head> <title>Countdown Timer</title> <link href="" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="main.css"> </head> <body> <header> <div> <h1> Countdown Timer </h1> </div> </header> <main> <div> <div> <h1> 10 Minute Timer </h1> <span>10:00</span> </div> <div> <button> Reset </button> <button> Start </button> </div> </div> </main> <script src="app.js"></script> </body> </html>21 Answer
setInterval is the best way to do what you want. It is printing "Done" with 2 second left because you are sec-- just after updating your DOM.
To solve the problem, you can just do sec-- and you DOM update at the end of your interval function like so
const value = document.querySelector("#time"); const startBtn = document.querySelector("#btn-start") const resetBtn = document.querySelector("#btn-reset"); startBtn.addEventListener('click', function(){ var minute = 1; var sec = 3; setInterval(function(){ if(sec < 0){ minute--; sec = 3; } if(sec <=9){ sec = "0" + sec; } if(sec == 0 && minute == 0){ alert("DONE!"); location.reload(); } value.innerHTML = minute + ":" + sec; sec--; }, 1000); }); resetBtn.addEventListener('click', function(){ location.reload(); })#main{ position: relative; display: flex; justify-content: center; align-items: center; padding: 20px; height: 100%; } .container{ position: relative; margin-top: 5%; } #title{ display: block; font-family: 'Roboto', sans-serif; font-size: 50px; font-weight: 600; color:rgba(0, 0, 0, 0.83); margin: 20px auto; padding: 0; } #time{ display: block; font-family: 'Roboto', sans-serif; font-size: 70px; text-align: center; margin: 20px auto 50px auto; } .function-buttons{ position: relative; display: flex; flex-direction: row; justify-content: center; align-items: center; } .reset-btn{ display: block; font-family: 'Roboto', sans-serif; font-size: 25px; width: 150px; background: #eee; margin: 0 10px; padding: 10px 30px; text-align: center; border-radius: 5px; border: none; outline: none; transition: .4s ease-in-out; cursor: pointer; } .reset-btn:hover{ background: red; color: #fff; } .start-btn{ display: block; font-family: 'Roboto', sans-serif; font-size: 25px; width: 150px; background: #eee; margin: 0 10px; padding: 10px 30px; text-align: center; border-radius: 5px; border: none; outline: none; transition: .4s ease-in-out; cursor: pointer; } .start-btn:hover{ background: #0096ff; color: #fff; }<!DOCTYPE html> <html> <head> <title>Countdown Timer</title> <link href="" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="main.css"> </head> <body> <header> <div> <h1> Countdown Timer </h1> </div> </header> <main> <div> <div> <h1> 10 Minute Timer </h1> <span>10:00</span> </div> <div> <button> Reset </button> <button> Start </button> </div> </div> </main> <script src="app.js"></script> </body> </html>