patternjavascriptModerate
Basic timer from one minute to 0
Viewed 0 times
onetimerfrombasicminute
Problem
I'm a beginner in JavaScript and I am sure that there is a better way to do it (basic one minute timer from 01:00 to 00:00 running from pageload):
JSFiddle
JSFiddle
window.onload=function(){
(function(){
setInterval(function(){
cro();
document.getElementById('unminut').innerHTML="0"+jocminut+":"+jocsecunda1+jocsecunda2;
},1000);
}());
}
var jocminut = 1;
var jocsecunda1 = 6;
var jocsecunda2 = 10;
function cro(){
if(jocsecunda1!=0||jocsecunda2!=0){
jocsecunda2 -=1;
while(jocminut==1){
jocminut-=1;
jocsecunda1 -=1;
}
while(jocsecunda2==-1){
jocsecunda1-=1;
jocsecunda2=9;
}
}
}Solution
You want to be careful with
Instead of starting with a counter and decrementing on each interval, you can calculate a time difference and then use
The following code calculates a completion date and then can calculate how many seconds are remaining.
I prefer to split logic into multiple functions so that the code is more readable. In your code what jumped out at me is three different bits of logic,
As a final note, once your timer hits zero, the interval no longer needs to fire. The following code cancel the interval using
All Together
The following is wrapped in a self-invoking anonymous function to prevent spilling code into the global scope.
setInterval() and setTimeout(), because javascript runs in only a single thread if the event loop is busy it won't fire the code in setInterval() or setTimeout() exactly as expected. This means your timer could take longer than you expected. Instead of starting with a counter and decrementing on each interval, you can calculate a time difference and then use
setInterval() to refresh the frontend. This will be more accurate.The following code calculates a completion date and then can calculate how many seconds are remaining.
//sets a completion date 60 seconds into the future
// Date.getTime() returns the time in milliseconds
var completion = new Date(new Date().getTime() + 60000),
function calculateSecondsRemaining() {
var now = new Date(),
//Math.max is used to prevent negative numbers from being returned
differenceInMilliseconds = Math.max(0, completion.getTime() - now.getTime()),
differenceInSeconds = Math.floor(differenceInMilliseconds / MILLISECONDS_IN_SECOND);
return differenceInSeconds;
}calculateSecondsRemaining() handles the complex logic that was once in cro(), but I feel that is is more readable. When dealing with time and numbers, tracking each digit can be tedious. I prefer to not deal with it at that level.I prefer to split logic into multiple functions so that the code is more readable. In your code what jumped out at me is three different bits of logic,
calculateSecondsRemaining(), updateDisplay(), and formatNumberTo2Places(). By spliting the functions up, the logic within your setInterval() is very small and very easy to understand.As a final note, once your timer hits zero, the interval no longer needs to fire. The following code cancel the interval using
clearInterval() once the timer has reached zero.var refreshIntervalId = setInterval(function () {
var secondsRemaining = calculateSecondsRemaining();
updateDisplay(secondsRemaining);
if (secondsRemaining <= 0) {
//clear timer once time expired
clearInterval(refreshIntervalId);
}
}, 1000);All Together
The following is wrapped in a self-invoking anonymous function to prevent spilling code into the global scope.
(function (window, document, undefined) {
var MILLISECONDS_IN_SECOND = 1000,
SECONDS_IN_MINUTE = 60,
timerLength = 60, //seconds
start = new Date(),
completion = new Date(start.getTime() + (timerLength * MILLISECONDS_IN_SECOND)),
pentruminut = document.createElement('span');
// add elements
document.body.appendChild(pentruminut);
function formatNumberTo2Places(n) {
//this assumes 1 or 2 digit positive numbers
var buffer = (n > 9) ? "" : "0";
return buffer + n;
}
function calculateSecondsRemaining() {
var now = new Date(),
//Math.max is used to prevent negative numbers from being returned
differenceInMilliseconds = Math.max(0, completion.getTime() - now.getTime()),
differenceInSeconds = Math.floor(differenceInMilliseconds / MILLISECONDS_IN_SECOND);
return differenceInSeconds;
}
function updateDisplay(secondsRemaining) {
var minutes = Math.floor(secondsRemaining / SECONDS_IN_MINUTE),
seconds = Math.floor(secondsRemaining % SECONDS_IN_MINUTE);
pentruminut.innerHTML = formatNumberTo2Places(minutes) + ":" + formatNumberTo2Places(seconds);
}
window.onload = function () {
var refreshIntervalId = setInterval(function () {
var secondsRemaining = calculateSecondsRemaining();
updateDisplay(secondsRemaining);
if (secondsRemaining <= 0) {
//clear timer once time expired
clearInterval(refreshIntervalId);
}
}, 1 * MILLISECONDS_IN_SECOND);
};
}(window, document));Code Snippets
//sets a completion date 60 seconds into the future
// Date.getTime() returns the time in milliseconds
var completion = new Date(new Date().getTime() + 60000),
function calculateSecondsRemaining() {
var now = new Date(),
//Math.max is used to prevent negative numbers from being returned
differenceInMilliseconds = Math.max(0, completion.getTime() - now.getTime()),
differenceInSeconds = Math.floor(differenceInMilliseconds / MILLISECONDS_IN_SECOND);
return differenceInSeconds;
}var refreshIntervalId = setInterval(function () {
var secondsRemaining = calculateSecondsRemaining();
updateDisplay(secondsRemaining);
if (secondsRemaining <= 0) {
//clear timer once time expired
clearInterval(refreshIntervalId);
}
}, 1000);(function (window, document, undefined) {
var MILLISECONDS_IN_SECOND = 1000,
SECONDS_IN_MINUTE = 60,
timerLength = 60, //seconds
start = new Date(),
completion = new Date(start.getTime() + (timerLength * MILLISECONDS_IN_SECOND)),
pentruminut = document.createElement('span');
// add elements
document.body.appendChild(pentruminut);
function formatNumberTo2Places(n) {
//this assumes 1 or 2 digit positive numbers
var buffer = (n > 9) ? "" : "0";
return buffer + n;
}
function calculateSecondsRemaining() {
var now = new Date(),
//Math.max is used to prevent negative numbers from being returned
differenceInMilliseconds = Math.max(0, completion.getTime() - now.getTime()),
differenceInSeconds = Math.floor(differenceInMilliseconds / MILLISECONDS_IN_SECOND);
return differenceInSeconds;
}
function updateDisplay(secondsRemaining) {
var minutes = Math.floor(secondsRemaining / SECONDS_IN_MINUTE),
seconds = Math.floor(secondsRemaining % SECONDS_IN_MINUTE);
pentruminut.innerHTML = formatNumberTo2Places(minutes) + ":" + formatNumberTo2Places(seconds);
}
window.onload = function () {
var refreshIntervalId = setInterval(function () {
var secondsRemaining = calculateSecondsRemaining();
updateDisplay(secondsRemaining);
if (secondsRemaining <= 0) {
//clear timer once time expired
clearInterval(refreshIntervalId);
}
}, 1 * MILLISECONDS_IN_SECOND);
};
}(window, document));Context
StackExchange Code Review Q#56381, answer score: 12
Revisions (0)
No revisions yet.