patternjavascriptMinor
Most efficient JavaScript countdown timer implementation
Viewed 0 times
javascriptcountdownefficienttimerimplementationmost
Problem
I have this timer working already(jsbin):
HTML:
JavaScript:
It seems a lot of code for just a timer. Is it possible to implement this with less code? Maybe with loops,
This code have problem and that is number of items in call stack when the time is big enough. I tried to write same code with
MY QUESTION is how to write this countdown with
HTML:
00:00JavaScript:
var o = document.querySelector('output'),
m = document.querySelector('#m')
s = document.querySelector('#s'),
start = document.querySelector('#start');
start.addEventListener('click', function(){
var mm = parseInt(m.value),
ss = parseInt(s.value);
timer = function(){
if(mm>0){
if(ss>0){
ss--;
}
else{
mm--;
ss = 59;
}
setTimeout("timer()", 1000);
o.value = (mm0){
ss--;
o.value = "00:" + (ss<10 ? '0' + ss : ss);
setTimeout("timer()", 1000);
}
}
}
timer();
}, false);It seems a lot of code for just a timer. Is it possible to implement this with less code? Maybe with loops,
Date object or something else?This code have problem and that is number of items in call stack when the time is big enough. I tried to write same code with
while or for but I couldn't get a good result.MY QUESTION is how to write this countdown with
for or while?Solution
document.querySelector("#id") is just a costly version of document.getElementById("id"). document.getElementById is the fastest way to select an element in your page (to the smartasses of you: besides document.head, document.body etc)document.querySelector("tagname") is also just a costly version of document.getElementsByTagName("tagname")[0]. Coincidentally, that's the second fastest way to get an element.document.querySelector and its array-like version are only useful for compound statements that are either too long or too difficult to do with "regular" DOM methods. One might argue that if your html is compound and complex, you're doing it wrong, and they'd most likely be right.If I were you, I'd also do future-you a favor and name your variables in a way that makes sense.
So, what do we have so far?
var output = document.getElementsByTagName("output")[0],
minutes = document.getElementById("m"),
seconds = document.getElementsById("m"),
start = document.getElementById("start");Moving on. The event listener is fine, now about parsing integers...
Try this piece of code:
parseInt("08"). The result is 0. Why, you ask? Well, if you don't pass a radix as a second parameter, parseInt will be nice enough to guess what you mean. parseInt sees that your string begins in a 0 and, of course, assumes the number is in octal! Why wouldn't it be?Point: either pass a radix like this:
parseInt(string, 10) or use parseFloat, which will always assume a decimal number. Whichever you like best, though I once heard that parseFloat is faster, dunno if that's true. I personally prefer parseFloat, for no obvious reasonSo we get:
var mm = parseFloat(minutes.value),
ss = parseFloat(seconds.value);Magnificent.
This line:
timer =Contains one of the most widely made errors in javascript. It's called implied global.
Basically, when you omit the
var statement, the variable definition list gets appended to the global object (which window refers to). So:function foo() { answer = 42; }
foo();
window.answer === 42;Never omit the
var statement. Even if you do wish to append a variable to the global object, do it explicitly (window.answer = 42;). Better that then let someone scratch their head trying to figure out how magic variables appeared from seemingly nowhere.Besides one more thing, your code is fine. What's that other thing, you ask?
setTimeoutWhen you pass a string to
setTimeout, it's the same as calling eval. It evaluates the string. That's slow and bad. Instead, pass a function to it:setTimeout(timer, 1000);Since
timer is a function, you can pass it around like any other value.Now, one might ask: "How do I call
func with parameters?"setTimeout(function() {
func(something, somethingElse);
}, 1000);
//or
setTimeout(func, 1000, something, somethingElse);About your actual code? it's fine. It's not the best piece of code I've ever, but it's not the worse as well. It's not too long for a timer, since all that's done is decrementing and calling itself again. I'd move the
< 10 checks to their own function, but maybe that's because I'm insane and not that "your way" is worse.tl;dr Your code contains errors, but other than that, it's fine.
Code Snippets
var output = document.getElementsByTagName("output")[0],
minutes = document.getElementById("m"),
seconds = document.getElementsById("m"),
start = document.getElementById("start");var mm = parseFloat(minutes.value),
ss = parseFloat(seconds.value);function foo() { answer = 42; }
foo();
window.answer === 42;setTimeout(timer, 1000);setTimeout(function() {
func(something, somethingElse);
}, 1000);
//or
setTimeout(func, 1000, something, somethingElse);Context
StackExchange Code Review Q#5531, answer score: 4
Revisions (0)
No revisions yet.