Timer countdown with javascript - 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;
};

Related

ReactJS: Continue timer in the background?

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.

Run a counter that is displayed on website

I want to run a counter on the back end of a website, so that it is constantly counting. I made a javascript counter (http://directinvent.com/counter/) which displays the desired result, although this resets whenever the site is loaded for each individual user.
The idea is simple enough. Run the counter back end and display the result live on front end. Any ideas on how this can be done?
The same way you would do a Timer in Javascript. You store when you start your counter. Then you recalulate the result on every update (request). No need to do the math every 1/10s. If nobody ask, this is useless.
Basicly, this will look like this :
long startTime = storeTimeFor(User);
return (currentTimeInSec - startTimeInSec) * incrementationPerSec
With this, you only need to store the startTime for each user (in database, file, or in cache if you want). On reset, just store the currentTime again.
This is how you would do a timer in lots of langage because incrementing a value every seconds (using a sleep(1000)) would not be precise since your thread will not be running all the time, your are not alone on the machine ;)
EDIT :
On the client side, I would not call to much the server, just ask the value store and do the math from the client with the same logic. Using a timeout to do the math over and over every X ms. See how to create a timer in Javascript if need, only the value calculate would change here.
The counter must be stored in the backend (in file or database), either it is a single counter or one counter per user.
When rendering the page, initially show the counter that is read from the backend.
If the speed of the counter is known and constant (e.g. increase 3 per second), then you can use javascript (setTimeout) to increase it every second. The backend will store a number and the time (unix time) when it was created, e.g. 120 at 08:00:00. If a user access the website at 09:00:15, you know that it is 3615 seconds later, so you render the initial page showing the starting counter as 120 + (3615/3) = 1325. After that, the javascript will increment and display it by 3 per second.
If the speed of the counter is unknown, then you need to periodically (e.g. once per 10 seconds) check to the backend via ajax, requesting the current value of the counter. You can immediatelly display that latest value (which means the counter will be updated once every 10 seconds). Or, if you want to give a sense of "live", you can display it incrementally with animation on the client side.
Example: current display shows 120. Ten seconds later, via ajax request you get a new value 150. The difference is 150-120 = 30 in 10 seconds. You can display the counter increased by 3 per second (120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150). You can also play with random increment to be more realistic, as long as the total increment is 30 in 10 seconds.
I solved this simply by getting the time of the day with the Date() variable, and multiplying the time of the day by the incremental constant desired. This way the scheme will automatically update every day with the correct number as wanted and all the users will be displayed the correct number at any given time.
function dotimer()
{
today=new Date()
window.setInterval("dotimer()",speed)
testMilli = today.getMilliseconds()
testSeconds = today.getSeconds()
testMinutes = today.getMinutes()
testHours = today.getHours()
totalCost = Math.round(testHours * 10800 + testMinutes * 180 + testSeconds * 3 + testMilli * 0.003);
document.getElementById("counterSeconds").innerHTML = totalCost;
}
Although this works for this purpose, it still manages to freeze the browser, so I will have to work out a way to handle this...

Creating a series of timed form submissions

I am interested in designing a timed quiz questions which submit themselves after 30 seconds or so. Following this other SO request I have coded the following:
<script>
var counter = 30;
var interval = setInterval(function() {
counter--;
// Display 'counter' wherever you want to display it.
document.getElementById("counter").innerHTML = "Timer:"+counter
if (counter == 0) {
// Submit form
test.submit('timeout');
}
}, 1000);
</script>
<p id="counter"></p>
This seems to work on most modern browsers. There is a problem however that this seems to work fine for the first question or form. I think the second form defines an additional function which causes the countdown to go twice as fast. Then the third, three times as fast, etc. Is there a way to ensure that this function is only defined once?
Thanks for any help you can provide. I am new to javascript so I apologize in advance if I have used the wrong terminology.
The first time you call setInterval(), it defines an interval that will decrement the counter by 1 every second. It doesn't stop once the counter reaches 0; it just keeps decreasing it every second. Then you call setInterval() again, which sets up another decrement of the same counter every second. So now the counter gets decremented twice per second: once because of the first interval you set up and another time because of the second interval. The effect just builds up as you add more intervals.
You can see the effect in this fiddle.
The solution is just to stop the interval once the counter reaches 0, before you set up another interval. Besides, there's no need to use the same counter variable for all the different intervals, so you can just declare a new variable each time in a narrower scope. Narrowing the scope of variables will minimize the risk of different pieces of code interfering with each other.
function startCountDown(){
// This counter is local to this invocation of the "startCountDown"
// function.
var counter = 10;
var interval = setInterval(function() {
counter--;
// Display 'counter' wherever you want to display it.
document.getElementById("counter").innerHTML = "Timer:"+counter
if (counter == 0) {
// Submit form
console.log("Form submitted!");
// Stop this interval so that it doesn't update the
// interface anymore (next interval will take care of that).
clearInterval(interval);
startCountDown();
}
}, 1000);
}
startCountDown();
This other fiddle shows the solution.

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.

Add a countdown in my scoring script (javascript/jquery)

I have the following script in a js file:
// Ad score
var score = 0;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += 100;
$('#score').text(score);
};
Now on each matching, 100 points are added to var score. This all works. Now I want to extend this a bit. As soon as the page loads I want to start a countdown to reduce the number of points (starting with 100) with 1 point a second for 60 seconds. So the minimum number of points a user can get is 40. When someone gets the points, the counter should reset and countdown again.
Example:
Page loads (timer starts from 100)
User has a match after 10 seconds (+90 points are added)
Counter resets and countdown from 100 again
User found a match after 35 sec (+65 points are added)
etc etc
Problem is, I have no idea how to do this :( Hope someone can help me with this.
The above is fixed, thanks all for helping!!!
The big picture is, you'll need to become pretty familiar with timeouts and intervals in javascript. This is the reference page I keep going back to when I need to refresh my memory: http://www.elated.com/articles/javascript-timers-with-settimeout-and-setinterval/
For your specific task, you'll probably want to use an Interval that triggers every 1000 milliseconds to calculate the second-by-second point reduction, and a separate Timeout for failure that resets every time the user completes their challenge.
Here are a few tips for working with timeouts and intervals that usually lead to followup questions:
When you set a timeout, always capture the return value (I think it's basically a random integer). Save it to some global var for convenience.
var failureTimer; // global var high up in your scope
failureTimer = setTimeout ( "gameOver()", 100000 ); // 100 seconds * 1000ms
Then in whichever method gets called when the player completes their challenge, you call this:
clearTimeout (failureTimer); // resets the timer and gives them another 100 seconds
failureTimer = setTimeout ( "gameOver()", 100000 ); // yes call this again, to start the 100 sec countdown all over again.
The second pain point you're likely to encounter when working with Timeouts and Intervals is how to pass parameters to the functions like gameOver() in my example above. You have to use anonymous functions, as described here:
Pass parameters in setInterval function
For more on anonymous functions, this is a good overview:
http://helephant.com/2008/08/23/javascript-anonymous-functions/
Good luck with your project! Let me know if you have any questions.
Here's some code without the use of timers. Call startCountdown() every time you want to re-initialize the count-down. Call getAvailableScore() when you want to fetch the current available score. You will have to decide what to do when the available score goes to zero.
var beginCountDownTime;
function startCountdown() {
beginCountDownTime = new Date();
}
function getAvailableScore {
var now = new Date();
var delta = (now.getTime() - beginCountDownTime.getTime()) * 1000; // time elapsed in seconds
var points = 100 - (delta / 60);
return(Math.round(Math.max(points, 0))); // return integer result >= 0
}
Maybe something like:
// Ad score
var score = 0;
var pointsAvailable = 100;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += pointsAvailable;
$('#score').text(score);
pointsAvailable = 100;
};
$(document).ready(function() {doTimer();});
function doTimer() {
setTimeout('reducePoints()',1000);
}
function reducePoints() {
if(pointsAvailable>40) {
pointsAvailable--;
}
doTimer();
}

Categories

Resources