I have a progressbar on the top of my page that I'm using to display the 1 minute timer used to refresh all the charts. The problem I'm having is that it never seems to be consistent.
function headerBar() {
var progressbar = $('#timerBar');
progressbar.progressbar({
value: 0
});
function progress() {
var val = progressbar.progressbar('value') || 0;
progressbar.progressbar('value', val + 5);
if (val < 99) {
setTimeout(progress, 3000);
}
}
progress();
}
headerBar();
setInterval(function () {
headerBar();
}, 60 * 1000);
The first time it runs fine, but the 2nd time seems to take 1/2 as long and every time after that seems to shave off time from the count.
here's the fiddle
Hurray! You're running into a kind-of race condition. Since
setTimeout()
does not guarantee to call every 3000ms likesetInterval()
(and even if it did, you'd still be subject to this problem), what most likely happens is that your interval callsheaderBar()
beforeprogress()
manages to stop itself from adding more timeouts! Here's a timeline to clear this up:Your progressbar is at 95!
timeout1
-> I better callprogress()
!progress()
-> Set progress bar toval + 5 = 100
!val(95) < 99
? Yeah! I better set a timeout to call myself againinterval
-> Thy time is up!headerBar()
!headerBar()
-> I set the progress to 0, and start moreprogress()
!progress()
-> Set progress bar to 5! Timeout to call myself again!progress()
-> Set progress bar to 10! Timeout to call myself again! (Oops, I never got toval > 99
to stop calling myself repeatedly!)time passes...
interval
-> It's time to go FASTER!headerBar()
!But how do you solve this problem? Well, firstly, you'll want to change your
progress()
check to useval + 5 < 99
. That still won't save you from problems like calling 20 timeouts taking longer than your one interval - you'll need some way to signal yourprogress()
to stop with all the progressing.One way to do this would be to add some sanity checks to
headerBar()
:This is a very hacky solution, however. A much more elegant one would be to use a closure!
In general though, you could still work on eliminating your interval(this would introduce a slight error in your timing), by modifying
headerBar()
to simply tell you when it's done.you need a clear interval.. like this
More examples of setTimeout on SitePoint here
Following your comment:
SEE DEMO