My script has a countdown timer, but has to be controlled by the server since the time can change at any time.
Usually counts down from 1 hour, but as it gets closer to 0, a user fired event from PHP will reset the time on MySQL database and the timer will shoot back to what ever time.
setInterval(function() {
$('#timer').load('api/getdata.php?clock=1');
}, 600);
As you can see, currently the countdown is returned by a PHP script, which is called every 600ms (1000ms sometimes appears to skip a second).
I need to have a simple text countdown (Minutes and seconds), which synchronizes with the PHP script. But as it gets less than 30 seconds, would need to sync every second.
Is this possible with JS?
This is the code for the PHP
$from = time();
$to = strtotime($row['clock']);
$Timer = date('i:s', $to - $from);
echo("$Timer");
I think the easiest way to tackle this ( correct me if I'm wrong anyone! );
Fetch the time from the server
Return [ json ]
[server_time]
[seconds_left]
[miliseconds_left]
Set these values on a function and make sure its called as your contract requires. As soon as this starts hitting < 60 seconds shorten the interval by division of (e.g. the amount of seconds, altough this might not be optimal :-) ).
60/60 = 1
50 / 60 = .73
30 / 60 = .5
etc...
If the miliseconds are really really crucial I'm afraid you would have to provide some more insight of what it actually is you are trying to accomplish?
Related
So I'm making a gaming where 2 people play a game, report their scores on the website, and the winner gets credited. Now I want to add a feature where if one person reports a result and the opponent fails to report his own result within 5 minutes, the website will automatically credit the person who reported the result.
Currently, I have coded a countdown timer in PHP and Javascript (and I prefer to do the countdown in Javascript and call the PHP function after the time elapse but it looks like I can't execute PHP code within Javascript but I would like to do this if possible).
I have equally written the countdown in PHP but it looks like PHP can't run in the background, so it's not updating the balance even after the time elapse.
Here's the PHP countdown as an example of what I want to do.
<?php
// Set the date we're counting down to
$countDownDate = strtotime('Dec 25, 2020 15:37:25') * 1000;
//Get current date
$now = time() * 1000;
// Find the distance between now an the count down date
$distance = $countDownDate - $now;
// Time calculations for days, hours, minutes and seconds
$days = floor($distance / (1000 * 60 * 60 * 24));
$hours = floor(($distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
$minutes = floor(($distance % (1000 * 60 * 60)) / (1000 * 60));
$seconds = floor(($distance % (1000 * 60)) / 1000);
// Output the result
echo days + "d " + hours + "h " +
minutes + "m " + seconds + "s ";
// If the count down is over, update user balance.
if ($distance < 0) {
$mysqli->query("UPDATE users SET bal=bal+50");
}
?>
The problem that this code doesn't update the balance in real-time after the time elapsed. It updates the balance each time the page is reloaded and keeps updating the balance non-stop.
WHEN I change the if the part to
if($distance ==0)
then it will not update at all because PHP is not doing a background check to know when the counter reaches zero and update the balance.
If you understand what I want to do please suggest how I can do this checking and auto-updating. I will also appreciate the sample code.
Thank you.
This is a fairly tricky concept so a few bits to put together, but common and doable. There's a better but more complex way, and an easier hack. I'll explain both.
The "running in the background" bit there are a couple of moving bits:
a) You need to have a process constantly running. While most people will say you need NodeJS or similar, there is no reason why you can't have a PHP script running constantly in the background - what you need to watch for is if the process dies, you need something to restart it (actually, exactly like NodeJS uses pm or systemd to restart - do the same thing with PHP). You script will just constantly "loop" (see below!) looking for work to do.
b) My preferred method, though, if to have a "cron" running every 5 minutes that executes a script, and that script has a timer that loops but will end the loop after 5 minutes and then exit. New process starts. If you do this, you need to factor overlap or minor gaps.
The "loop" mentioned above must not burn your CPU, so you need to handle receiving messages in the right way. Ideally this needs to be ran by a queue, but there are other options.
a) Use a queue system such as RabbitMQ + deal letter queue (although we've moves to AWS SQS as we're hosted on AWS and that allows delayed messages) that holds the message and delivers after 5 minutes. Your script above will be listening for the message.
b) If you don't want to set up a queue, as you know the minimum time is 5 minutes, you could use the "5 minute cron" method and look for messages on start. If there is a message, "sleep" until that message should be processed, process it and look for the next one. If no messages, exit and the cron will repeat in 5 minutes. (Note: sleep is not recommended in a normal PHP script as it holds open HTTP processes, but for a single running background process like this, it's perfect).
Realtime feedback is another thing you can hack, or do correctly.
a) The correct way is to have another constantly running script that accepts socket connections, and JS will connect to the socket. PHP can be used very well for sockets, but NodeJS here does have much better support and you'll find easier. Start the socket server script, use Socket.io or similar in Javascript and connect to the socket server. When you update a score, push the result to the correct client.
b) The easier way is a polling system. Have JS poll the server regularly to see if there are updates. (Socket.io has a fallback to polling as well). This adds more strain on your server, but much easier to set up.
I have a bit of code, which refreshes my HTML page, everytime there is a new minute i.e. when seconds == 0.
<head>
<script>
function reload(){
location.reload();
}
function refresh(){
var d = new Date();
var s = d.getSeconds();
if (s == 0) {setTimeout(reload(), 1000)};
}
</script> </head>
<body onload="refresh(), setInterval('refresh()',1000)">
However, when it refreshes, it refreshes an infinite amount of times in the time that seconds == 0. I have tried to implement "setTimeout", in order to prevent this from happening - and so that it only refreshes once. However, this did not work and it is still refreshing an infinite amount of times while s == 0. Does anyone have any more ideas to prevent this from happening? Any questions, just ask. Thanks
If I understand correctly, you don't want to refresh after 1 minute from loading but refresh when second = 0.
You don't have to call refresh function constantly via interval.
We have current second. So, if we subtract from minute, we can find remaining seconds to new minute.
60 - d.getSeconds();
Then convert into milliseconds, set timeout, and page will be refresh exactly at new minute.
setTimeout(function() { location.reload() }, 1000 * (60 - d.getSeconds()));
If so important you can consider add/subtract milliseconds with d.getMilliseconds()
For JavaScript, you can simplify this down to:
setTimeout(() => {
window.location.reload(1);
}, 60 * 1000);
However a very simple solution not using JS is
<meta http-equiv="refresh" content="60; URL=https://example.com/">
In general the refreshin is not a nice way to do things. have you considered using asychronous calls and refreshing your DOM with JavaScript instead of reloading the whole page?
However if you want to pursue this route I'd take the current starting time as a base and check from here is 1 second has passed already.
const t0 = performance.now();
function refresh(){
if ((performance.now() - t0) >= 1000) {
location.reload();
}
}
However you'll need to call refresh untill this happens.
As for the "don't understand" comment, I cleand up a litle and I'll add some explanation here:
The first line is outside of all functions, so it sets a variable "globally", as it never changes I use a cosntant (instead of a variable) for speed and readability. It sets the current time in ms insode t0
const t0 = performance.now();
In your funcion I use the same command to get the ms again, and substract the formerly saved ms from it. If the new number is more than 1000 bigger than the original, a second has passed and it can do the reload.
if ((performance.now() - t0) >= 1000) {...
I have made a countdown timer. It uses the date function to get the current time. Then it stores that time in another var. This new var gets changed hours/minutes/seconds, so the format should be the same as the date function.
Then I turn both variables into time since counting, in milliseconds.
Then I substract the current date from the new date thingy, to get the time difference from both variables in milli seconds. This should be the difference from the current time to the target time.
After this, I will turn the difference into a readable hours/minutes/seconds timeformat, which will be displayed in a div. Also added a piece of code for allowing an blinking countdown timer, which will give 5 minutes extra time if the timer has run out. (this countdown timer should be part of a larger script, doing things)
BIG PROBLEM IS: The timer works. Does everything I want it to do. But it's very laggy! It skips displaying seconds, even if I set the setTimeout to 10 ms. I also use a clock using the same timer set-up (different vars), and that clock doesn't skip any time, with a setTimeout of 1000 ms...
Tryed to make some calculations smaller, even read alot about the setTimeout and setInterval drift in javascript, but this doesn't explain my current problems. (using setTimeout for a chat, to reload messages every 500 ms, and that works like a charm so my computer/client/server can handle smaller then 1000 ms times)
Skipping seconds happens on IE and firefox. Other countdown timers (which don't do what I want them to do) also run fine in my browser. What's the problem here?!?
https://jsfiddle.net/77cnvq82/
function startMyFunction() {
setTimeout(myFunction, 100);
}
In this example, the speed has been set to 100ms
The actual issue is in your rounding and math, not in the display code itself.
If you change your display line to:
timerShowRemaining = timerShowRemaining+timerHours+":"+timerMinutes+":"+timerSeconds
+ (new Date());
It will display the current time and you'll see the seconds count up evenly, even as your calculated numbers jerk and lag.
Context
I m actually developping an application in which people have tasks to make in a day. It's just like "wash the window, clean the floor" etc.. etc...
Each task has a recurrence, and needs to be done at least one time in this period.
Example :
Task 1 has to be done every 15 days. Actually, it's been 16 days that it has not been done. So an event should be emitted.
My client needs to be alerted when something hasn't been done , on a time event, with a proper manner
I know that cron tasks exist for this, I could run one at midnight everyday, and send a mail alert with this. But what if I need to be exactly 15 days ? seconds by seconds ?
I really need efficiency without running this kind of scripts every days.
Does it exist a better way ?
The simplest way of working with timed events in Javascript is through setInterval.
You should keep in mind that the interval size parameter of the function is a 32-bit integer, which limits its size to 2147483647.
This parameter is given in miliseconds, so your maximum interval is about 24 days (2147483647 / (1000 [ms in a sec] * 3600 [secs in an hour] * 24 [hours in a day]).
All you have to do is:
setInterval(function(){
doWhateverYouNeedHere();
}, interval);
Edit
You could workaround the interval size parameter by stacking recursive setTimeout calls with a lower interval:
setTimeout(function(){
setTimeout(function(){
doWhateverYouNeedHere();
setTimeout(function(){
setTimeout(function(){
doWhateverYouNeedHere();
}, not_so_big_interval);
}, not_so_big_interval);
}, not_so_big_interval); // max 24 days
}, not_so_big_interval); // max 24 days
// In total, your function will run every 48 days.
I am making a little time killer project for myself, as a way to wait for a forum post.
var factsArray = ['MIT has created a 3D version of Scratch, called StarLogo', 'Duck echos DO quack', 'Ostriches never stick their head in the sand', 'The cigarrete lighter was invented before the match']
var i = 0;
function start() {
while (i < 20) {
setTimeout(function(){document.getElementById('content').innerHTML = factsArray[Math.floor(Math.random() * factsArray.length)];}, 3000);
i = i + 1;
}
setTimeout(function(){document.getElementById('content').innerHTML = "Sixty seconds are up! Go and post!";}, 3000);
}
That's my code; so far, it will only show one item from the array and stop there.
What I want it to do is display one fact from my factsArray every 3 seconds, until 60 seconds has passed, then it will display "Sixty seconds are up! Go and post!".
Why is my code only showing one fact, not one every 3 seconds?
setTimeout is quasi-asynchronous, this code adds 20 timeouts at nearly the same time so they also end at the same time. You will want to set only one timeout and start the next one in the timeout's callback if the total timeout has not been reached yet. Similarily the last statement should be added if the total timeout has been reached.
You could also work with setInterval and clearInterval to implement this.