Why does my digital clock function leak memory? - javascript

I have a digital clock function that takes the hours, minutes, and seconds from a JSON result, parses them as integers, does math on them (add 1 to the seconds every time it's looped through, if the seconds is 0, add 1 to minutes, etc.). After that math I parse these three variables as strings so I can then pad them with leading 0's for a result that looks like
10:05:34
(hours, minutes, seconds).
I use this method rather than datetimes because JS will always parse datetimes in local time, but the three variables are based on server time.
function countTime(){
timeSeconds = parseInt(timeSeconds);
timeMinutes = parseInt(timeMinutes);
timeHours = parseInt(timeHours);
timeSeconds = (timeSeconds + 1);
if (timeSeconds == 60){timeMinutes = (timeMinutes + 1); timeSeconds = 0;};
if (timeMinutes == 60){timeHours = (timeHours + 1); timeMinutes = 0;};
//convert from 24 to 12 hour time, and "0" hour to 12
if (timeHours > 12){
timeHours = (timeHours - 12)
};
if (timeHours == 0){
timeHours = 12;
};
//back to strings so that 0s can be padded
timeSeconds = timeSeconds.toString();
timeMinutes = timeMinutes.toString();
timeHours = timeHours.toString();
//pad 0s
if (timeSeconds <= 10 && timeSeconds.length < 2)(timeSeconds = ("0" + timeSeconds));
if (timeMinutes <= 10 && timeMinutes.length < 2)(timeMinutes = ("0" + timeMinutes));
if (timeHours <= 10 && timeHours.length < 2)(timeHours = ("0" + timeHours));
//show time
timetext = timeHours + ":" + timeMinutes + ":" + timeSeconds
$('#BT').html(timetext);
};
Which is called by this function that sets it at an interval:
function updateTime() {
countTime();
timeInt = setInterval(countTime,1000);
console.log('updated time from server');
};
timeInt is initialized globally before so I can clear that interval on a window focus event.
When I take this function out of my page, I have a memory use of around ~20kb that stays fairly certain. With this function included, memory use starts around 40kb and increases every second (which I think indicates a memory leak. . .). updateTime is called on a nonstandard interval (around every 45 minutes by the success callback of the AJAX call that gets timeHours,timeMinutes, and timeSeconds. Do I have a scope problem? Am I redifining variables needlessly when I have countTime on an interval?

You are leaking the interval timers. You need to call clearInterval before initializing it again.
function updateTime() {
countTime();
clearInterval(timeInt); // Here
timeInt = setInterval(countTime,1000);
console.log('updated time from server');
};

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.

Displaying current time in JS w/ given functions

Need to display current time in JS with the given functions.
Internet searches showed JS using Date() and Time() for gathering the info, but the date and time are not showing up in the HTML when run it.
"use strict";
var $ = function(id) { return document.getElementById(id); };
var displayCurrentTime = function() {
var now = new Date(); //use the 'now' variable in all calculations, etc.
var Date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
var hours = now.getHours()+ ":" + now.getMinutes() + ":"
+ now.getSeconds();
//Ok, problem now is getting HTML to call it up?
};
var padSingleDigit = function(num) {
if (num < 10) { return "0" + num; }
else { return num; }
};
window.onload = function() {
// set initial clock display and then set interval timer to display
// new time every second. Don't store timer object because it
// won't be needed - clock will just run.
};
Instructor's instructions:
"Note that to convert the computer’s time from a 24-hour clock to a 12-hour clock, first check to see if the hours value is greater than 12. If so, subtract 12 from the hours value and set the AM/PM value to “PM”. Also, be aware that the hours value for midnight is 0.
The starter project has four functions supplied: the $ function, the start of a displayCurrentTime() function, a padSingleDigit() function that adds a leading zero to single digits, and the start of an onload event handler.
In the displayCurrentTime() function, add code that uses the Date object to determine the current hour, minute, and second. Convert these values to a 12hour clock, determine the AM/PM value, and display these values in the appropriate span tags.
Then, in the onload event handler, code a timer that calls the displayCurrentTime() function at 1 second intervals. Also, make sure that the current time shows as soon as the page loads. (some comments have been included in the starter code to guide you on where to place things)."
In order to grap an html element you first need one. So i made a tag with an id of "clock". I then set an interval, running every 1000 milis (1 second) to give me the correctly formatted time.
clock = document.getElementById("clock");
let hours, minutes, seconds;
function checkDigits(num, hours) {
if (num < 10) {
return "0" + num
} else {
if (hours) {
return num - 12
}
return num
}
}
function updateTime() {
date = new Date();
hours = checkDigits(date.getHours(), true)
minutes = checkDigits(date.getMinutes())
seconds = checkDigits(date.getSeconds())
clock.innerHTML = hours + ":" + minutes + ":" + seconds;
}
window.onload = function() {
setInterval(function() {
updateTime()
}, 1000);
}
<h1 id="clock"></h1>

How to tween a timestamp to a specific time

I have a fake clock on screen with a time of day:
<div class="time">9:14<sup>am</sup></div>
I want to make a function to be able to tween that time to another arbitrary time,
so that the clock would actually progress through the seconds and hours until it hit the new time(pseudocode):
var currentTime = {
time: 9:14am
}
function changeTime(newTime){
TweenMax.to(currentTime,.5,{
time: newTime
});
}
changeTime(12:32pm);
So in the case above, the minutes would go up by one until they hit 60, then increment the hours by one and reset to zero, then increment again to 60, etc, until they hit 12:32 (with the am switching to pm at 12:00pm).
Is there a way to do this with tweenmax and a timestamp? Or would I need to construct a custom function? Or perhaps is there a better way to tween time?
You can use something like this (and improve it, I did this quickly).
<script>
var hour, minute, second, meridian, isAm;
isAm = true;
hour = 0;
minute = 0;
second = 0;
function timerLoop () {
second++;
if(second > 59) {
second = 0;
minute++;
}
if(minute > 59) {
minute = 0;
hour++;
}
if(hour >12) {
hour = 1;
isAm = !isAm;
}
// update labels
meridian = 'a.m.';
if(!isAm) meridian = 'p.m.';
console.log(hour + ':' + minute + ':' + second + ' ' + meridian);
setTimeout(function() {
timerLoop();
}, 1000);
}
timerLoop();
</script>
I tested it for 2 mins only but the that part was working.
You'll probably want to add leading zero's to the single digits as I haven't done that. And once it is running as you want you can look at adding animations or fades to style it a bit better.

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.

Categories

Resources