Timer with performance.now() - javascript

I want to realize timer using performance.now because Date.now depends on users clock (performance.now doesn't), and "Date.now-way" may crash the timer, when user changes system clock.
And I want to store timer in localStorage. When user close tab or browser and open it, timer have to resume.
Important condition: I want to take into account the time, when the browser/tab was closed. For example, user close browser, when timer value is 10 sec. After 10 sec user open the browser - timer value should be 20 sec.
This is the problem, that I faced.
This is code without using localStorage:
const timerNode = document.getElementById('timer');
const initialTimestamp = performance.now();
setInterval(() => {
const seconds = getSeconds(initialTimestamp);
timerNode.innerHTML = seconds;
}, 200);
function getSeconds(initialTimestamp) {
return Math.round((performance.now() - initialTimestamp) / 1000);
}
<div id='timer'></div>
Is there any way to store timer in localStorage using performance.now and resume it in cases, that I mentioned above (and observing the condition)?
Or maybe there is another way to get UNIX timestamp, that is not depends on system clock?
To demonstrate problem with Date.now() run this code and change system time, for example, set date to few days ago. You will see, that value of the timer is negative.
const timerNode = document.getElementById('timer');
const initialTimestamp = Date.now();
setInterval(() => {
const seconds = getSeconds(initialTimestamp);
timerNode.innerHTML = seconds;
}, 200);
function getSeconds(initialTimestamp) {
return Math.round((Date.now() - initialTimestamp) / 1000);
}
<div id='timer'></div>

Yes, you would use localStorage for this to persist across browser sessions.
You would use setItem to set the initial time and getItem to access it in new browser sessions. When the new browser session starts, you would check if a previous initial time existed. If it did, use it; if it didn't, create it.
var initialTimestamp = localStorage.getItem('initialTimestamp');
// If we previously set an initialTimestamp, convert it from string to number.
if (initialTimestamp) {
initialTimestamp = parseInt(initialTimestamp);
}
// If we never previously set an initial timestamp, create one now.
else {
initialTimestamp = performance.now();
localStorage.setItem('initialTimestamp', initialTimestamp);
}

Related

Basic javascript countdown timer that is accurate even on mobile while screen is off [duplicate]

This question already has answers here:
How to create an accurate timer in javascript?
(15 answers)
Closed last month.
Basically, I am trying to emulate something just like https://www.online-stopwatch.com/countdown-timer/ for use in a web app. Works fine using settimeout, but when the screen is turned off on Android, for example, javascript stops running (or is severely delayed) so a 5 minute timer might take 15 minutes to ring, or 5 minutes to ring.
Any solution would be much appreciated. I've also tried support workers but those also get stopped when the screen is off.
I can't figure out what technology they are using on the aforementioned website, but it looks like animation or something, and from my tests IS accurate even when the screen is off.
Thank you!
Edit: Nope - I did a number of more tests and even their timer does not work reliably on android.
Edit: the question was actually about a website being able to trigger some kind of sound, alert or notification while the phone screen is off, not about keeping track of the time. That is not possible due to permissions (thankfully).
Apps have access to additional permissions that might make this feasible to do as an app.
Original answer basically answering "How to measure elapsed time in a browser on mobile from clicking a button even when screen is off or browser is closed":
What I would do is as soon as the timer is started you store the timer start time in localstorage and then use a setInterval to update the UI based on your stored value. I would make this accurate to the second to avoid a very heavy UI update cycle. Something like this works (tested on Android / Opera)
(Cannot use a snippet due to localStorage allow-same-origin)
<div>-</div>
<button>Start</button>
<script>
const out = document.querySelector("div")
const btn = document.querySelector("button")
let timer, startTime;
btn.addEventListener("click", () => {
// If timer is started, reset
if (timer) {
clearInterval(timer)
}
startTime = Date.now()
localStorage.setItem("startTime", startTime)
timer = setInterval(() => {
const now = Date.now()
const millis = now - Number(localStorage.startTime)
const seconds = Math.floor((millis / 1000) % 60)
const minutes = Math.floor((millis / 1000 / 60) % 60)
out.innerText = minutes + ":" + seconds
}, 1000)
console.log("Started interval timer", timer)
})
</script>
You could make it even work between browser shutdowns by checking the localstorage during page load

Countdown timer with remote server - React native

I have an app that requires countdown timer. Due date comes from my back-end with rest api. I need to coundown remaining time in my react native app. But I can't use smart phone's time. Because user can be in different timezone / country etc. How i can use server's due date response for react native?
Should I send also remaining time in seconds to user? So I can countdown that remaining time every second?
https://www.example.com/getDueDate [POST]
returns:
Y-m-d H:i:s (future) time like 2021-05-20 23:40:40
If I use classic countdown approach for javascript, I need to use smart phone's time. But I don't want to use that.
NTP server approach can be tricky for react-native side. It just simple counter.
Why not send both the server's current time and the due date? Then start your timer from there?
That being said, the time will still be off by the roundtrip time between your user and the server (which will depend on their internet connection and your server's response time).
Yes, it is possible to get time. I'm also using rest api (token base authentication and expiry token after certain time). I'm checking as given below
var l_currentDateTimeSeconds;
l_currentDateTimeSeconds=((new Date().getTime() - "your_time_from_api") / 1000);
if (parseInt(l_CurrentDateTimeSeconds) < parseInt(your_time_from_api))
{
//failure case ;
}
else
{
//Success case;
}
output of time (in variable) will be in seconds. Visit given below link, it may be help
https://aboutreact.com/react-native-get-current-date-time/
This is the technique i use and it's really effective.
Step 1.
Send due date from server (5pm)
Send current time from server (4pm)
Step 2.
Check clients current time (3pm)
Subtract currentTime(server) - currentTime(client) and call it timeOffset
Step 3.
setInterval to run every second using the code example below.
//import useState, useEffect from react-native
const [timer,setTimer]=useState();
var serverExpiryDate="'the time the event will expire gotten from server";
var currentTimeAtServer="the time you got from server via api";
var currentTimeAtDevice=new Date().getTime();
const timeOffset= currentTimeAtServer - currentTimeAtDevice;
//timeOffset is the time difference between the user's clock and the server clock. Calculated when user received response from server.
useEffect(() => {
let interval = setInterval(() => {
setTimer(() => {
let endT = new Date(serverExpiryDate).getTime(); //time from server;
let nowT = new Date().getTime(); //current time on user've device
nowT = nowT + timeOffset; //VERY IMPORTANT, helps to sync user's time with server.
let remaining = endT >= nowT ? Math.floor((endT - nowT) / 1000) : 0;
let stopCheck = remaining === 0 ? clearInterval(interval) : null;
return remaining;
});
}, 1000); //each count lasts for a second
return () => {
clearInterval(interval);
};
}, []);
console.log(timer) //this will be decreasing every second

How to initialize a cookie with changing argument

I have a code that needs to run a count-down timer, the counter needs to count down 15 min per user even if he\she leaves the page.
this is the cookie initialize line:
document.cookie = "name=timerCookie; timeLeft=" + initialTime + "; expires=" + expires;
and this is how I update the cookie:
document.cookie = "name=timerCookie; timeLeft=" + timeLeft + "; expires=" + expires;
when I try to read the cookie I get "name=timerCookie"
am I setting the cookie correctly?
can I use cookie this way?
EDIT****:
apparently, cookie can contain only 1 segment(aka timeLeft) by removing the name value the issue was solved.
Well, I came up with this solution while I was offline and before I learned what your use case actually is.
I was thinking it would be better to use localStorage since MDN says:
"Cookies were once used for general client-side storage. While this was
legitimate when they were the only way to store data on the client, it
is recommended nowadays to prefer modern storage APIs."
Since your server needs to know about the user's "time remaining", you probably want cookies after all (unless you can just have the browser update the server at unload time), but maybe you can adapt this idea to your purpose.
I was also thinking that "even if he/she leaves the page" meant that the timer should keep ticking while they're away -- but this part should be relatively easy to fix.
I'm including this as HTML (to copy/paste) because SO snippets are sandboxed and won't run code that uses localStorage.
<!DOCTYPE html><html><head></head><body>
<p id="display">__:__</p>
<script>
let expires = localStorage.getItem("expires"); // Gets the stored expiration time
const display = document.querySelector("#display"); // Identifies our HTML element
// Makes a helper function to treat dates as accumulated seconds
const getSecondsSinceEpoch = ((date) => Math.floor(date.getTime()/1000));
// Sets the expiration time if countdown is not already running
if(!expires){
expires = getSecondsSinceEpoch(new Date()) + (60 * 15); // 15 minutes from now
localStorage.setItem("expires", expires);
}
// Calculates how long until expiration
let pageLoadedAt = getSecondsSinceEpoch(new Date());
let secondsRemaining = parseInt(expires) - pageLoadedAt;
// Starts the countdown (which repeats once per second)
setInterval(countdown, 1000);
function countdown(){
// When time expires, stops counting and clears storage for the user's next visit
if(secondsRemaining === 0){
clearInterval();
localStorage.clear(); // You don't want this here -- it resets the clock
}
else{
// Until time expires, updates the display with reduced time each second
display.textContent = formatTime(--secondsRemaining);
}
}
function formatTime(time){
let mins = Math.floor(time/60).toString();
let secs = Math.floor(time%60).toString();
secs = secs.length == 2 ? secs : "0" + secs; // Ensures two-digit seconds
return `${mins}:${secs}`
}
</script>
</body></html>

Keep setInterval running while tab is completely closed

Trying to make a real-time clock that uses setInterval (centisecond based) but I want it to run when the tab is not open or even when the computer is off. Is this even possible? If you have heard of the game cookie clicker, I'm pretty sure it at least runs when the tab is completely closed out of, so how do I replicate it, and if I cant, are there any other methods I can use to make a digital clock?
It's not possible to run code while a tab is closed or the machine is off. The best you could do is to periodically save information to localStorage, and then, whenever the script runs again, retrieve the saved information from localStorage and run all the calculations necessary to get up-to-date. Or, if it's as simple as a date, you might just check Date.now() every time the tab is opened.
Here's a very simplistic implementation:
const info = localStorage.savedInfo
? JSON.parse(localStorage.savedInfo)
: { count: 0, date: Date.now() };
const now = Date.now();
if (info.date < now) {
info.count += Math.floor((now - info.date) / 1000);
info.date = now;
}
function tick() {
info.count++;
console.log(info.count);
info.date = Date.now();
localStorage.savedInfo = JSON.stringify(info);
setTimeout(tick, 1000);
}
tick();
https://jsfiddle.net/gn9128ea/1/

Persist setTimeout and setInterval across Node.js restarts

I set quite a few server-side timeouts with setTimeout and setInterval for each connected user that can last for 10-30 seconds. If the Node.js instance restarts in the middle of one of these timeouts, they are obviously all cleared on restart, which can cause some issues for these users. How would I go about persisting these timeouts, or are there any modules that already help with this?
setTimeOut takes delay as parameter, so when setting timeout, capture currentServerTime + delay say serverTriggerTime and persist this in DB. Then, on restart of server, create the same timer using the serverTriggerTime.
Then, delay = serverTriggerTime - currentServerTime, use this delay to set new timer.
When setting timer
const date = Date.now();
const serverTriggerTime = date + delay; // time in milliseconds
On server restart:
serverTriggerTime = // retrieve from DB.
newDelay = serverTriggerTime - Date.now();
Also, set new timer only if newDelay >= 0, meaning the trigger time has not reached and will happen after newDelay time.
I would store the start times and durations in Redis and restart incomplete timers when your application reloads. Some Redis modules:
https://github.com/joyent/node/wiki/modules#wiki-db-nosql-redis

Categories

Resources