I am trying to impl a timer that makes use of requestAnimationFrame to keep the timer on even while user has moved onto other tabs and windows.
I am facing an issue where unless I directly make use of the callback from the the requestAnimationFrame WebAPI it just doesn't work! I am not really sure where I went wrong in understanding this Web API.
Working Impl
var count = 0;
var updateTimer = function (timestamp) {
count = timestamp;
let s = Math.floor((count / 1000) % 60);
let m = Math.floor((count / 60000) % 60);
let h = Math.floor(count / 3600000);
let formattedHours = h < 10 ? "0" + h.toString() : h;
let formattedMinutes = m < 10 ? "0" + m.toString() : m;
let formattedSeconds = s < 10 ? "0" + s.toString() : s;
timer.textContent = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
prevTimestamp = timestamp;
rAF_ID = requestAnimationFrame(updateTimer);
}
In the picture below you can see the log when I hit the "Finish" button. This is after I have moved away from the tab for a couple of seconds.

Non-Working Impl
var milliseconds = 0;
var seconds = 0;
var minutes = 0;
var hours = 0;
let rAF_ID;
var prevTimestamp = 0;
var updateTimer = function (timestamp) {
// Calculate the elapsed time between calls i.e., since previous frame in milliseconds
var elapsedTime = timestamp - prevTimestamp;
// Here we needed an additional variable called "milliseconds" to capture the timer progress because "timestamp" typically represents the number
// of milliseconds elapsed since the page started loading or since a specific point in time (e.g., the beginning of the page's execution).
milliseconds += elapsedTime;
if (milliseconds >= 1000) {
milliseconds = 0;
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 24) {
hours = 0;
}
}
}
}
// console.log(timestamp, milliseconds, seconds, elapsedTime);
let formattedHours = hours < 10 ? "0" + hours.toString() : hours;
let formattedMinutes = minutes < 10 ? "0" + minutes.toString() : minutes;
let formattedSeconds = seconds < 10 ? "0" + seconds.toString() : seconds;
timer.textContent = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
prevTimestamp = timestamp;
rAF_ID = requestAnimationFrame(updateTimer);
}
In the picture below you can see the difference in the log and the timer.

I can't really work with the timestamp alone because it is always returning milliseconds since the page loading and that is no good, since after pausing the timer and restarting doesn't start the timer where I left.
This is how my startTimer looks like:
async function startTimer() {
if (!isRunning) {
if (milliseconds === 0 && seconds === 0 && minutes === 0 && hours === 0) {
timer.textContent = "00:00:00"
counter.textContent = "00:00:00"
}
isRunning = true;
startTimestamps.push(new Date().getTime());
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
await sleep(1000);
rAF_ID = requestAnimationFrame(updateTimer);
updateCounter();
logActivity();
}
}
You can have a look at a working version that has the problem of stopping when the tab is out of focus! https://iamsmkr.github.io/seesaw/