Countdown server side best practices - javascript

Problem
I have a countdown that is server side and needs to be shown on the client. First i made it using socket.io basically emitting it every 100 milliseconds. Now i really like this but i fear there might be significant performance downgrade to instead just emit a signal and having the client make the countdown but this brings another problem which is not being able to see the countdown value until it resets. Is emitting every 100ms really that bad of a practice or is this ok ?
Edit
I need it server side because of authentication and consistency for all users loop is small 40 secs followed by a 10 sec pause. I need to know if users have performed the action in that period

Honestly, I would recommend doing it by the client because it's easiest and better even if they had some type of disconnection from the server
function msToTime(duration) {
var seconds = parseInt((duration/1000)%60),minutes = parseInt((duration/(1000*60))%60),hours = parseInt((duration/(1000*60*60))%24),days = parseInt(duration/(1000*60*60*24));
var hoursDays = parseInt(days*24);
hours += hoursDays;
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + ":" + minutes + ":" + seconds;
}
function startCountdown(){
setInterval(function(){
var a = new Date().getTime();
var now = new Date();
var b = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 24, 0, 0, 0).getTime();
document.getElementsByClassName("text")[0].innerHTML= msToTime(b-a);
},0);
}
<input onclick="startCountdown()" type="submit">
<p class="text" ></p>
Function From here: https://stackoverflow.com/a/19700358/14746601

Related

Timer not working when using readline-sync (Javascript)

I am making a game that keeps track of the time you take to complete the game, however i realised that the timer does not continue when i am asking for input.I tried to wait 10 seconds before typing a input but after i input a value the time is 00:00.Must i create a separate file for the timer or is there a possible way for the timer to run.Please help thanks!
var readline = require('readline-sync');
seconds = 0;
minute = 0;
timer = setInterval(() => {
if (seconds == 60) {
seconds = 0;
minute++;
}
seconds++;
}, 1000);
var input = readline.question('Input:');
clearInterval(timer);
//String to show time
if (minute < 10 && seconds < 10)
time = '0' + minute + ':0' + seconds;
else if (minute < 10 && seconds >= 10)
time = '0' + minute + ':' + seconds;
else if (minute >= 10 && seconds < 10)
time = minute + ':0' + seconds;
else
time = minute + ':' + seconds;
console.log(time);
It is easier just to create a Date object with new Date() and substract it from another Date created after the user Input.
var dateStart = new Date();
var input = readline.question('Input:');
var difference = new Date() - dateStart(); // time elapsed in milliseconds
For more complex cases I'd recommend looking up the libraries moment.js or date-fns.

Why does my javascript clock crash after a minute?

I have double checked and tested on jshint for syntax errors and such. I have also compared my code to others who created the same clock, but did not see any differences that would cause my clock to crash. I do not understand what is causing this problem.
$(document).ready(function(){
function displayTime() {
var currentTime = new Date();
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
var miridiem = "AM";
var clockDiv = document.getElementById('clock');
if(seconds < 10) {
seconds = "0" + seconds
}
if(minutes < 10) {
minutes = "0" + minutes
}
if (hours > 12) {
hours = hours - 12
miridiem = "PM"
}
if (hours === 0) {
hours = 12
}
clockDiv.textContent = hours + ":" + minutes + ":" + seconds + " " + miridiem;
setInterval(displayTime, 1000);
}
displayTime();
});
<body>
<div id="clock"></div>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script>
</body>
Warning: snippet will eat your memory. Don't forget to stop it.
https://jsfiddle.net/9cp9m43h/
You're just misunderstanding the usage of setInterval and setTimeout.
As some commenters mentioned, you could just change your current implementation to use setTimeout and it would function pretty well.
However, in my opinion, the best solution would be to change the way your code works, so that setInterval works correctly:
$(document).ready(function(){
function displayTime() {
var currentTime = new Date();
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
var miridiem = "AM";
var clockDiv = document.getElementById('clock');
if(seconds < 10) {
seconds = "0" + seconds
}
if(minutes < 10) {
minutes = "0" + minutes
}
if (hours > 12) {
hours = hours - 12
miridiem = "PM"
}
if (hours === 0) {
hours = 12
}
clockDiv.textContent = hours + ":" + minutes + ":" + seconds + " " + miridiem;
}
displayTime();
setInterval(displayTime, 1000);
});
I feel this is better because:
this is what setInterval was designed for: performing the same action over and over at a specific interval.
calling setTimeout manually to reset the timer leaves you open to some clock skew; if it takes a millisecond for your displayTime to run before it sets the timeout, then after 1000 seconds you're probably going to be about 1 second off.
a function called displayTime() sounds like all it's doing is displaying the time--there's nothing to hint that it's also creating a long-term side-effect. The separation of concerns feels better if the timer is set outside of that method.
The effects of displayTime() are easier to test independently when it's not creating asynchronous side-effects.
I think your setInterval() is in the wrong place. You placed it inside the function, which is registering 60 interval monitors per minute so the memory is crashing. If you wanted to trigger the next timeout after the function has been called, you can do that using setTimeout(), within the displayTime() function. But if you do setInterval(), you want that to be called at the same level that your initial displayTime() function is called.
See my fiddle: https://jsfiddle.net/9cp9m43h/3/
every time displayTime() is called it starts a new Interval that calls displayTime() every second.
Therefore every second the function is called twice as often as the time before. After 60 Seconds this is Math.pow(2, 60) //=> 1152921504606847000 times.
Hmm, i'm having a hard time figuring out how it crashed with the setInterval() within the displayTime() function, but working completely fine outside the function.
Because in this case displayTime() is not calling itself not even a roundtrip over setInterval. So it stays a single Interval, and therefore a single function-call every second.

Count-Up Timer on each page load from 0

I want to implement a count-up timer JS code that starts counting at each load page from 0. The code which I've now is like this:
var secondsTotal = 0;
setInterval(function() {
++secondsTotal;
var minutes = Math.floor(secondsTotal / 60);
var seconds = Math.floor(secondsTotal) % 60;
var milliseconds = Math.floor(secondsTotal) % 1000;
document.getElementById('counter').innerHTML = minutes + ":" + seconds + "." + milliseconds;
}, 1000);
The output format should be: 00:00.0
mm:ss.ms
So, how to output the result like above format (minutes and seconds should be exactly printed in two digits format)?
If you want to do it per-page, you're almost there. Right now, your code does not allow you to track milliseconds, as your setInterval runs every second. What I would recommend instead is something like this:
(function() {
var counter = 0,
cDisplay = document.getElementById("counter");
format = function(t) {
var minutes = Math.floor(t/600),
seconds = Math.floor( (t/10) % 60);
minutes = (minutes < 10) ? "0" + minutes.toString() : minutes.toString();
seconds = (seconds < 10) ? "0" + seconds.toString() : seconds.toString();
cDisplay.innerHTML = minutes + ":" + seconds + "." + Math.floor(t % 10);
};
setInterval(function() {
counter++;
format(counter);
},100);
})();
This does a couple of things to allow your code to run 10 times per second:
The output element, #counter, is cached and not retrieved every iteration
The formatting is kept to arithmetic operations only - modulo and division.
This now also adds leading zeroes.
If you would like to keep this counter running page-per-page, consider using document.cookies to pass the final value from page to page.
Fiddle
This serves as a good first version. However, you may want to:
Pause/re-start your timer
Reset your timer
Have multiple timers
For this reason, I will add a slightly more complex form of the above code, which will allow you to manage multiple timers. This will make use of a few OO concepts. We will use a TimerManager object to "host" our timers, and each Timer object will have a link to the manager.
The reason for this is because every timer will depend on the same setInterval() by doing it this way, rather than to have multiple setInterval() calls. This allows you to cut down on wasted clock cycles.
More on this in about 5 minutes!
Counting seconds that way isn't guaranteed to be accurate. The setInterval method can drift on you based upon the JS engine's ability to complete its other tasks. Not sure what your use case is, such as how long you expect to count up, but it's worth taking note of. See Will setInterval drift? for a detailed explanation.
I'd recommend you check out the momentjs plugin # http://momentjs.com/ and update your code to something like the following
var startTime = moment();
var el = document.getElementById('counter');
setInterval(function() {
var ms = moment().diff(startTime),
min = moment.duration(ms).minutes(),
sec = moment.duration(ms).seconds();
ms = moment.duration(ms).milliseconds();
min = (min < 10) ? "0" + min.toString() : min.toString();
sec = (sec < 10) ? "0" + sec.toString() : sec.toString();
ms = ms.toString().substring(0,2); // change this if you want to expand ms counter display
el.innerHtml = min + ":" + sec + "." + ms;
}, 50);
You're free to update the interval, and your milliseconds display without adjusting your calculations.

Refreshing JS code to display correct data on screen

I'm using script below to countdown from given time and display how many hours+minutes+seconds left for timeout on the script in real-time.
Counting down woks perfectly fine but the problem I'm facing is, when using next and previous buttons on browsers, the time doesn't get refreshed and I see old time instead. It either shows previous time or later.
I'm aware that next and previous buttons on browsers don't refresh pages but how can I overcome this issue?
JS
function timeout_warning(login_timeout)
{
var counter = 0;
var total_seconds = 0;
var colour = '';
var interval_id = '';
interval_id = setInterval(function ()
{
counter++;
total_seconds = login_timeout - counter;
hours = parseInt(total_seconds / 3600 ) % 24;
minutes = parseInt(total_seconds / 60 ) % 60;
seconds = parseInt(total_seconds % 60, 10);
remaining = (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes) + ":" + (seconds < 10 ? "0" + seconds : seconds);
if (minutes == 0 && seconds == 0)
{
document.getElementById('font_timeout').innerHTML = 'Timeout';
window.clearInterval(interval_id);
}
else
{
document.getElementById('font_timeout').innerHTML = remaining + 'sec';
}
}, 1000);
}
HTML BODY
<body onload="timeout_warning('1800')">
Without a live example I can only give an opinion to the solution. You might want to us JavaScript to load the remaining time from a cookie so that when a browser arrow is clicked the code will pull the time from the cookie and not from the cached data.
A solution has already been posted on this and uses a form to store data in the page to see if the user has pressed the back button. It sets some form data and if the page goes back, it can tell if that data is already set, and if it is, it needs to force a reload (so your timer will start again).

How to add days this countdown script so that it becomes DD-HH-MM-SS?

I have this script in jQuery:
// Auction countdown script
$(function () {
var remaining = $("#countdown").text(),
regex = /\d{2}/g,
matches = remaining.match(regex),
hours = matches[0],
minutes = matches[1],
seconds = matches[2],
remainingDate = new Date();
remainingDate.setHours(hours);
remainingDate.setMinutes(minutes);
remainingDate.setSeconds(seconds);
var intvl = setInterval(function () {
var totalMs = remainingDate.getTime(),
hours, minutes, seconds;
remainingDate.setTime(totalMs - 1000);
hours = remainingDate.getHours();
minutes = remainingDate.getMinutes();
seconds = remainingDate.getSeconds();
if (hours === 0 && minutes === 0 && seconds === 0) {
alert('done');
}
$("#countdown").text(
(hours >= 10 ? hours : "0" + hours) + ":" +
(minutes >= 10 ? minutes : "0" + minutes) + ":" +
(seconds >= 10 ? seconds : "0" + seconds));
}, 1000);
});
Now, this takes a string and makes a HHMMSS countdown for it. I want it to be DDHHMMSS but I can't seem to get it to work. Can anybody point me in the right direction?
Thanks!
If you like to create countdown function by yourself then Please take reference from below links to build right logic :
http://stuntsnippets.com/javascript-countdown/
http://www.hashemian.com/tools/javascript-countdown.htm
OR
its better to use one of below jQuery plugin
http://www.littlewebthings.com/projects/countdown/
http://keith-wood.name/countdown.html
Hope it helps
ALL D BEST
The basic problem is that Date objects are for dates and times, not time intervals. So setDate() and getDate() operate on the date of the month, not a count of days.
You could simply use integers and divide by the number of seconds in a minute, minutes in an hour, etc. Or you could implement a TimeInterval object, as described here:
http://i-programmer.info/programming/javascript/3088-a-javascript-timeinterval-object.html
Use toString for that:
var remainingDate = new Date();
remainingDate.toString("dd-MM-yyyy HH:mm:ss");
This returns for example 01-08-2012 14:08:22

Categories

Resources