ReactJS: Continue timer in the background? - javascript

I have a create-react-app that has a setInterval that runs a tick() function every 1000 millisecond. The tick() function decrements the sessionTime state by one. It works perfectly fine when the browser tab is in the foreground but it loses count in the background (not counting after a certain period). How do I allow it to continue running? Is this even the right approach to a timer in React?

You might be running out of your time budget?
Anyway, a more reliable way is not to rely on the interval being a specific time; check current new Date() every time you execute your tick, calculate how much time has passed since last tick or since a certain remembered start time (or remaining to certain target time), and act accordingly.
For example, if you want a session to expire in 30 minutes,
let now = new Date();
const second = 1000;
const minute = 30 * second;
let expiryTime = new Date(now.getTime() + 30 * minute);
and then in your tick just check whether new Date() > expiryTime. This way, it does not matter how often your tick routine runs.

Related

Timer run every 5 minutes React JS (javascript)

I want to set timer every 5th minute. Example: timer countdown 5 minutes only at time 00:00 , 00:05 , 00:10 , 00:15 etc. in 00:17 timer should countdown 3 minutes
how setTimeout and setInterval with that provision?
I would like to do it programmatically, in React JS using javascript, anyone can help me?
When you want a function to run at a specific clock time, like every full minute, it's usually best to use setTimeout with sequential calls. That way you can work out the time to the next whole "tick" and set the timeout for that interval. This stops small lags caused by the system being busy accumulating, making the timing drift.
Using setInterval lags accumulate so the timing slowly drifts. The first run needs setTimeout anyway to start it at the right time (e.g. next full tick).
Here's a simple example to run a function on whatever tick you want, specified in milliseconds. The example is every 30 second tick but if you want 5 minutes just call it with 3e5 (i.e. 5 * 60 * 1000 = 300,000 which is the number of milliseconds in 5 minutes). Then it will run at the next full tick and every tick after that until cancelled.
setTimeout also returns an identifier (timer id, not used in the example) that you can use to stop it if necessary.
/**
* Run a function on every tick at specified interval. First
* call of fn is on next tick. May be a few ms late depending
* on system load when fn due to run.
*
* #param {Function} fn - function to call
* #param {number} tick - clock tick to run function on in milliseconds
* e.g. 30 secs = 3e4, 1 min = 6e4, 5 min = 3e5
*/
function onEveryTick(fn, tick) {
// Time to next tick
let getTick = () => tick - (Date.now() % tick);
// Currie function to sequentially call itself
let f = () => {
fn();
setTimeout(f, getTick());
}
// First call after required lag
setTimeout(f, getTick());
}
// Call on 30 second tick
onEveryTick(() => console.log('Tick ' + new Date().toString()), 3e4);

Browser seems to cache DateTime

I realized that a change in system time is not immediately reflected in javascript, event if I use a new Date object. It is only updated every minute.
var fakeElapsed = 0;
$(document).ready(function(){
var oldTime = 0;
function fakeTimeLoop(time){
fakeElapsed+=(time-oldTime);
oldTime = time;
$("div").html(fakeElapsed);
}
var clock = new Date();
var start = clock.getTime();
oldTime = clock.getTime();
setInterval(function(){
var clock2 = new Date();
var end = clock2.getTime();
var elapsed = end-start;
if(elapsed%5===0){
fakeTimeLoop(end);
}},
1
);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div></div>
</body>
Time code, if you would turn time forward (or backwards), it takes a minute to change the time elapsed.
Is there anyway to update to the system time every second?
Edit: for those who are confused, a change in system is not reflected immediately on Chrome and Opera, but on IE and Mozzila, it is immediately reflected, I assume its order to avoid expensive system calls every time it needs to build a new Date object.
What I am looking for: is that anyway to get the current system time in chrome/opera or detect a change in system time immediately?
It's not exactly clear to me what you're trying to accomplish, but your setInterval is programmed to execute every millisecond (the second parameter is in milliseconds), but browsers treat any value less than 10 as equal to 10. Even with that restriction, the timing isn't guaranteed to be exact, so the function may well execute every 11, 12, 13, etc. milliseconds.
When you change your computer date/time and refresh the web page, new Date() will not return correct date/time. After 20-25 seconds it will return correct time. Probably it is a browsers' bug (I tested on Windows 10, Edge an Chrome).

Timer countdown with javascript

I have a timer countdown with javascript.It countdowns from 3 minutes.But if user reloads the page I have to resume the countdown.I mean user loaded the page and countdown starts from 3 minutes then after 1 minute user reloads the page countdown should start from 2 minutes.How can I do this ? I don't want any code I need the algorithm.
After each second change, you need to save the state of the counter into some kind of persistent storage.
I'd just use:
localStorage['time_left'] = JSON.stringify(time_left);
When you load the page, first you try to load the state of the timer.
time_left = JSON.parse(localStorage['time_left']);
And then check whether the value was even stored.
if(time_left===undefined){// you're on fresh instance
Would also be good idea to clear the stored variable after the timer finishes.
Good luck :>
You need to persist the current time left to the end of the timer somewhere where you can access it later, even after the page has been refreshed. Local storage comes to mind, but other methods may be possible.
Instead of setting the timer to 3 minutes, you set an interval to run a function every second. You save two pieces of information to your storage:
Amount of time till the end, perhaps in seconds ( 180s for 3 minutes)
Amount of time already passed since the start (0 by default, incremented with each interval)
Every time the interval function ticks, you increase the total time passed and check if it is already higher than the total amount expected. Do your custom actions when the condition is true. Do not forget to clear the interval, otherwise it will keep going on indefinitely and uselessly.
var remaining = localStorage.remaining || 180;
window.setInterval(function(){
remaining = remaining - 1;
document.querySelector('#countdown').innerHTML = remaining;
}, 1000);
window.onbeforeunload = function(){
// Save remaining time as the window is closed or navigated elsewhere
localStorage.remaining = remaining;
};

Run JS function every new minute

So I've got this JavaScript clock I'm working on and I want it to be perfectly synced with the clients' system clock. I know how to get the current time using a Date object and I know how to run the update function every 60000 milliseconds (1 minute). The thing is that the client might load the page when half a minute has already passed, making the clock lag behind with 30 seconds. Is there any way to just run the update function when the minute-variable actually changes? (I only want minute-precision.)
How I get the current time:
var time = new Date();
var currentHour = time.getHours();
var currentMinute = time.getMinutes();
How I run the update function every 60000 ms:
setInterval(update,60000); //"update" is the function that is run
When the user logs in, get the current time and seconds of the minute, subtract 60 to get the remaining seconds, then multiply to set the timer
var time = new Date(),
secondsRemaining = (60 - time.getSeconds()) * 1000;
setTimeout(function() {
setInterval(update, 60000);
}, secondsRemaining);
First, you have to understand that timers in javascript are not guaranteed to be called on time so therefore you cannot be perfectly synced at all times - javascript just isn't a real-time language like that. It is single threaded so a timer event has to wait for other javascript that might be executing at the time to finish before a timer can be executed. So, you must have a design that still does as best as possible even if the timer is delayed (called later than it's supposed to be).
If you wanted to try to stay as close to aligned and do the fewest screen updates and be the most friendly to mobile battery life, I'd suggest this self-aligning code which realigns itself on each tick based on the time remaining until the next minute change:
function runClock() {
var now = new Date();
var timeToNextTick = (60 - now.getSeconds()) * 1000 - now.getMilliseconds();
setTimeout(function() {
update();
runClock();
}, timeToNextTick);
}
// display the initial clock
update();
// start the running clock display that will update right on the minute change
runClock();
This has the advantage that it only calls the update once on the next minute boundary.
Working demo: http://jsfiddle.net/jfriend00/u7Hc5/
var time = new Date();
var currentHour = time.getHours();
var currentMinute = time.getMinutes();
var currentSecond = time.getSeconds();
var updateinterval = setInterval(startTimer,(60-currentSecond)*1000);
function startTimer(){
clearInterval(updateinterval);
setInterval(update,60000);
}
function update(){
var time = new Date();
console.log(time.getSeconds());
}
I would set an interval to run each second, then check if time.getSeconds() == 0. This way you could execute an action whenever a new minute starts, based on the client time.

can setInterval drift over time?

I have 2 node.js webservers. I cache data inside webservers. I sync the cache load/clear based on system time. I have done time sync of all my hosts.
Now I clear cache every 15 mins using following code:
millisTillNexthour = "Calculate millis remaining until next hour"
setTimeout(function() {
setInterval(function() {
cache.clear();
}, 60000*15);
}, millisTillNexthour);
My expectation is even if this process runs for ever, cache will be cleared every 15th minute of each hour of the day.
My question is: can setInterval drift over time?
For eg: right now it clears cache at 10:00 10:15 10:30 10:45 11:00 ......
Can it happen that instead of 10:15 system time, setInterval gets executed at 10:20 system time when it was supposed to clear cache at 10:15??
I am not sure how this works. Please shed some light. I hope I explained my question well.
I'm probably more than a bit late to the party here, but this is how I solved this particular time-slipping problem just now, using a recursively called setTimeout() function instead of using setInterval().
var interval = 5000;
var adjustedInterval = interval;
var expectedCycleTime = 0;
function runAtInterval(){
// get timestamp at very start of function call
var now = Date.now();
// log with time to show interval
console.log(new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') + " runAtInterval()");
// set next expectedCycleTime and adjustedInterval
if (expectedCycleTime == 0){
expectedCycleTime = now + interval;
}
else {
adjustedInterval = interval - (now - expectedCycleTime);
expectedCycleTime += interval;
}
// function calls itself after delay of adjustedInterval
setTimeout(function () {
runAtInterval();
}, adjustedInterval);
}
On each iteration, the function checks the actual execution time against the previously calculated expected time, and then deducts the difference from 'interval' to produce 'adjustedInterval'. This difference may be positive or negative, and the results show that actual execution times tend to oscillate around the 'true' value +/- ~5ms.
Either way, if you've got a task that is executing once a minute, and you run it for an entire day, using this function you can expect that - for the entire day - every single hour will have had 60 iterations happen. You won't have that occasional hour where you only got 59 results because eventually an entire minute had slipped.
setInterval is definitely drifting (although I agree that it should not be). I'm running a Node.js server with an interval of 30 seconds. On each tick, a few async web requests are made which from beginning to end take roughly 1 second. No other user-level/application processing happens in the intervening 29 seconds.
However, I notice from my server logs that over the course of 30 minutes, a drift of 100ms occurs. Of course, the underlying operating system is not to blame for the drift and it can only be some defect of Node.js's design or implementation.
I am very disappointed to notice that there is a bug in the NodeJS implementation of setInterval. Please take a look at here:
https://github.com/nodejs/node/issues/7346#issuecomment-300432730
You can use Date() object to set specific time and then add a certain number of milliseconds to the date.
It definitly can because of how Javascript works (See Event Loop)
Javascript event loop executes the setInterval queue when other queued events are finished. These events will take some time and it will effect your setInterval function's execute time and it will eventually drift away as time passes.
setInterval should not drift in a perfect world. It might be delayed due to other things taking up system resources. If you need a more precise solution to what you have, use the clock() function to " calibrate " your nodes.

Categories

Resources