cheepmanzee
cheepmanzee

Reputation: 31

setInterval() for Stop Watch Timer with JS that works outiside the window

I'm creating a JS stopwatch and everything works fine except that the timer actually pauses when I leave the window. How can make It run even when I'm browsing other pages. (Need that for Pomodoro clock project).

Thank you in advance!

let seconds = 00;
let tens = 00;
let minutes = 00;
let getSeconds = document.querySelector('.seconds');
let getTens = document.querySelector('.tens');
let getMinutes = document.querySelector('.minutes');
const start = document.querySelector('.start'),
      stop = document.querySelector('.stop'),
      reset = document.querySelector('.reset');
let interval;

start.addEventListener('click', () => {
   clearInterval(interval);
   interval = setInterval(startTimer,10);
})

stop.addEventListener('click', () => {
   clearInterval(interval);
})

reset.addEventListener('click', () => {
   clearInterval(interval);
   getMinutes.innerHTML = '00';
   getSeconds.innerHTML = '00';
   getTens.innerHTML = '00';
   tens = 0;
   seconds = 0;
   minutes = 0;
})

function startTimer() {
   tens ++;
   if (tens <= 9) {
      getTens.innerHTML = '0' + tens;
   }
   if (tens > 9) {
      getTens.innerHTML = tens;
   }
   if (tens > 99) {
      seconds ++;
      getSeconds.innerHTML = '0' + seconds;
      tens = 0;
      getTens.innerHTML = '0' + 0;
   }
   if (seconds > 9) {
      getSeconds.innerHTML = seconds;
   }
   if (seconds > 59) {
      minutes ++; 
      seconds = 0;
      getSeconds.innerHTML = '0' + seconds;
      getMinutes.innerHTML = '0' + minutes;
     
   }
   if (minutes > 9) {
      getMinutes.innerHTML = minutes;
   }
}

Upvotes: 0

Views: 947

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074148

You can't, browsers reduce or suspend timers running on inactive tabs. But even if the timer weren't suspended, assuming it runs reliably without being delayed, as that code does, isn't reliable. The JavaScript UI thread can be busy with other things, delaying the timer callback.

Instead, record when you started and when your timer callback is called, look at what time it is and figure out what value the timer should show based on that interval.

For example, this shows you how many seconds (total) the timer has been running. Start it, switch away from the tab, and then come back. I've made the timer interval fairly large in hopes that when you come back, you can see the old value updated to an accurate one. You can also use the "Cause Delay" button to tie up the JavaScript UI thread to see the display catch up when the busy-wait is done.

const btnStart = document.getElementById("btn-start");
const btnStop  = document.getElementById("btn-stop");
const btnDelay = document.getElementById("btn-delay");
const display  = document.getElementById("display");

let startTime = 0;
let timer = 0;

btnStart.addEventListener("click", () => {
    btnStart.disabled = true;
    btnStop.disabled = false;
    startTime = Date.now();
    tick();
    timer = setInterval(tick, 1000);
});

btnStop.addEventListener("click", () => {
    btnStart.disabled = false;
    btnStop.disabled = true;
    clearInterval(timer);
    timer = 0;
});

btnDelay.addEventListener("click", () => {
    // Busy-wait to cause a perceptible delay in
    // handling the timer
    // >>>NEVER DO THIS IN REAL CODE<<<
    btnDelay.disabled = true;
    const label = btnDelay.value;
    btnDelay.value = "Delaying...";
    // Very brief delay so the browser shows the
    // button disabled
    setTimeout(() => {
        const stop = Date.now() + 3000;
        while (Date.now() < stop) {
            // wait
        }
        btnDelay.disabled = false;
        btnDelay.value = label;
    }, 60);
});

function tick() {
    const elapsed = Math.round((Date.now() - startTime) / 1000);
    display.textContent = `${elapsed} second${elapsed === 1 ? "" : "s"}`;
}
<input type="button" id="btn-start" value="Start">
<input type="button" id="btn-stop" value="Stop" disabled>
<input type="button" id="btn-delay" value="Cause Delay">
<div id="display"></div>

Upvotes: 2

Related Questions