Reputation: 5784
Can you please take a look at following code and let me know how I can avoid the delay on only FIRST time of this counting down process?
As you can see the counter works fine but there is a delay on first time starting.
var sec = 20;
var timer = setInterval(function() {
$('#box').text(sec--);
if (sec == -1) {
$('#box').css('color','blue');
clearInterval(timer);
}
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box">20</div>
Upvotes: 0
Views: 1098
Reputation: 2477
To answer your question: Instead of an anonymous function, use a function expression. This will allow you to call that function anywhere in your code.
To dig a bit deeper: Instead of setInterval, consider setTimeout. Intervals can queue up when the going gets tough (leading to some interesting results), timeouts won't. See John Resig's post on timers for more info.
A timeout setup (see a comparison in the snippet below):
var secs = 20,
onTimeout = function() { // a function expression
console.log(secs);
if (secs--) {
// do things before complete here (~1x per sec)
timeout = setTimeout(onTimeout, 1000);
} else {
// do things after complete here
}
}, timeout;
onTimeout();
If you're after accuracy in a modern browser, use requestAnimationFrame.
/**
OK: INTERVAL
**/
var secs_i = 20,
onInterval = function() {
console.log(secs_i, 'Interval');
if (secs_i--) {
// do things before complete here (~1x per sec, may queue and run in fast succession)
} else {
return clearInterval(interval);
// do things after complete here
}
},
interval = setInterval(onInterval, 1000);
onInterval();
/**
BETTER: TIMEOUT
**/
var secs_t = 20,
onTimeout = function() {
console.log(secs_t, 'Timeout');
if (secs_t--) {
// do things before complete here (~1x per sec)
timeout = setTimeout(onTimeout, 1000);
} else {
// do things after complete here
}
}, timeout;
onTimeout();
/**
BEST: ANIMATION FRAME (IE9+ everything else)
**/
var secs_a = 20,
onAnimationFrame = function() {
time = secs_a - (window.performance.now() - init)/1000;
console.log(time.toFixed(2), 'Animation Frame');
if (time > 0) {
// do things before complete here (~60x per second)
af = window.requestAnimationFrame(onAnimationFrame);
} else {
// do things after complete here
}
}, af, init = window.performance.now(), time;
onAnimationFrame();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>console.log=function(log,id){$('h1[data-id="'+id+'"]').text(log);};</script><h1 data-id="Interval"></h1><h1 data-id="Timeout"></h1><h1 data-id="Animation Frame"></h1><style>h1:before{content:attr(data-id)": ";}</style>
Upvotes: 0
Reputation: 4360
Use --sec
instead of sec--
, so that the changed value will be set.
The reason why this is working is well described here: ++someVariable Vs. someVariable++ in Javascript
So your code should look like this:
var sec = 20;
var timer = setInterval(function() {
$('#box').text(--sec);
if (sec == -1) {
$('#box').css('color','blue');
clearInterval(timer);
}
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box">20</div>
Upvotes: 7
Reputation: 1978
Another option - move piece of code to separate function
var sec = 20;
var execution = function() {
$('#box').text(sec--);
if (sec == -1) {
$('#box').css('color','blue');
clearInterval(timer);
}
}
execution(); // Run first time without delay
var timer = setInterval(function() {
execution(); // every next run should be done with delay
}, 1000);
Upvotes: 3
Reputation: 386730
put the callback in a separated function and call it immediately after/before, as you like, the setInterval();
Upvotes: 0