Sometimes you just need a progress bar. While working on a HTML5 game last year we had the issue where we were making an ajax request for two very large files and then processing them both. Roughly the times were a minute for each file on a slow connection and then another 30 seconds to process each file. The first problem was we needed a progress bar quickly. Our second problem was each jump, assuming I wrote a proper progress bar, would be 25% and the time between might not solve our last problem. The user needed something to indicate progress was being made. So I suggested we fake the progress bar. The funniest thing was after I implemented what I'm about to describe, both my manager and the client commented that "it seems to load faster now". Like I said, sometime you just need a progress bar.
How do you fake a progress bar?
What you need is a function that never reaches 1.0
and a good guess as to what a "long"
time is for your process. In our case I used a variation of 1-(1/t)
and adjusted so
that it reached 80% after 60 seconds.
start = Date.now() el = document.getElementById('progress-bar') rate = 4 / 60000 done = 0 interval = setInterval(-> elapsed = Date.now() - start progress = 1 - (1 / (elapsed * rate + 1)) if (done > 0) if (done == 4) progress = 1.0 clearInterval(interval) else progress += (1 - progress) * done / 4 done++ width = Math.floor(progress * 400) el.style.width = width + 'px' , 250) # Here we fake the process finishing early in 45 seconds setTimeout(-> done = 1 , 45000)
Here's a working copy where I've adjusted the times to 80% in 30 seconds and the process finishing early in 20 seconds:
What exactly is going on?
The first thing we need is to adjust our equation. The thing to note is that t
in 1-(1/t)
must be greater than 1
, so first we adjust our equation
1 - 1 / (rate * time + 1) == 0.8
and solve for rate
as a function of time
rate = 4 / time
You'll notice in the above code the fake finish in 45 seconds. This starts a counter done
that will take the next 1 second (4 * 250ms) to finish up our progress bar and then clear the interval. This is accomplished by taking the remaining progress 1 - progress
times the number of 4ths done / 4
and adding this to progress
:
progress += (1 - progress) * done / 4;
Further thoughts
Because we were short on time I choose a simple equation (the first one that occured to me) and the simplist implementation. It's possible this could be cleaned up even further.
For one, since we knew 4 distinct things that needed to complete I could have implemented the fake progress as a sub-progress for each of the main "things" that completed, moving the bar 25% for each one that finished, but using a 1-(1/t)
type equation to keep the bar moving during the load and processing stages.
It's probably just the fact that I had to watch it so many times during development and test, but after a while it starts to look fake. I could, also, have added a bit of "noise" to the progress bar movement to make it look a little more random.