Summary : A patchy, inconsistent picture. I would invite all browser manufacturers to take a good look at these tests. I do not wish to decry any browser as such, as I think all browsers today are pretty amazing. My rude comments below are simply concerning their performance on this point alone.
If you have any comments on this blog entry, please leave them at the above link.
This entry sets out my explorations of how you can implement progress bars in browsers, and how (shockingly), Internet Explorer has IHMO the best developer experience at present in this regard. Indeed I would plead with other browser mamanufacturers to look at how IE does the following: -
- Giving access to the
window.open()has returned. At present you cannot dynamically update the DOM without calling
- Making windows returned by
window.open()run in a separate "thread" like a
showModelessDialogas a more configurable version of
It won't happen, but you can dream.
Overall, my experience of the browsers in this test was:-
- Internet Explorer - Hands down the best IMHO.
- Opera - Implements
progresselements how I would expect. Slick.
- Firefox - Not bad.
- Chrome/Safari - Total rubbish. Could not get any of the new technologies involving
progresselements to work. Could be my mistake, but then, Opera did work.
Statement of the Requirement
As a result I have long-running functions, and I want to keep the user updated.
These updates may be:-
- a graphical progress bar
- a stream of log messages
In effect I want a Progress Dialog Box (or should I say, Monolog Box), with a stop button to let the user cancel an operation mid-flow.
Nothing unusual here.
Statement of the Problem
This means that you cannot update the display, whilst the function is running.
So no progress bar.
progress element in HTML5 was for this purposes, but not all browsers seem to agree.
My ideal solution
- It can be integrated simply into your existing code, with no need for complex continuation-style programming or message passing (e.g. using
Approaches to the problem
I discuss briefly below the approaches to the problem, and you can come to your own conclusion.
This web page contains the code to test against the browsers: Test Page
This web page lets you browse the test page source: Test Page Source
Approach 1 : showModelessDialog (SUCCESS - IE ONLY)
This is by far the best solution I have found, and pretty much meets my needs, except for the fact that it requires a child window to be spawned.
It has the following advantages:-
- The dialog window seems to run in a separate "thread", so it can be updated independently.
- The dialog window is very configurable (more than for
- You can immediately start writing to its
This is great in a HTA file, runing in an unsecure browser instance.
In an normal HTML file (running in a secure browser instance), you have to remember to point the URL in
showModelessDialog to a small empty htm file (mine is called
stub.htm) in the same domain as the parent page, otherwise you will get cross-domain scriping access denied messages.
"about:blank" fails as this is seen as a different unsecure domain by IE.
Unfortunately this approach is IE only, and the clever folks benhind HTML5 saw fit to omit it from their specification.
Approach 2 : showModalDialog (FAIL - ALL BROWSERS)
showModalDialog will eventually be supported by all browsers, but this fails entirely because the "modal" element obviously blocks things from happening.
The modal dialog calls back to the parent window to call the loop function. Unfortunately as the call comes from the modal dialog in the first place, it cannot update itself. A call to a window
setTimeout on the parent window will not work, because the timeout function will not be called until the dialog is closed!
So this is a complete NO-GO.
Approach 3 : window.open (SUCCESS - IE ONLY!)
Again this is a good solution, but, surprisingly, IE only.
It is less promising than showModelessDialog because:-
- window.open shows a new window in the task bar
- you cannot exclude the address bar
- it is slighly slower to load because it is a whole new browser instance
Why IE only?
Because in all other browsers, the child window is not run in a separate "thread". So it will not update its display until the parent window process completes.
It can of course be made to work for other browsers, if you combine it with Approach 5 below, but that really defeats the object.
In any case, it is a pain to implement for other browsers. If you carry out a
window.open() itself returns. Oh yes, if you look for
window.document, immediately after calling
window.open, you will find it, but it feels like a "dummy" object, and any changes you make to its DOM will be completely ignored. So the only way to implement it is to first open the window, exit the function, and allow the child window to complete its loading, and use a
Another problem is with Chrome, which seems to have a problem with locally stored files in the same folder directory (it does not treat them as the same domain). See: Issue raised on Chrome website.
Approach 4 : iframe (FAIL - ALL BROWSERS)
Again, another problem is with Chrome, which seems to have a problem with locally stored files in the same folder directory (it does not treat them as the same domain). See: Issue raised on Chrome website.
Approach 5 : setTimeout and continuations (SUCCESS - OF A SORT - ALL BROWSERS)
This is the universally recommended approach if you search, and involves using the continuation passing style of programming.
What you do is call your loop for a "chunk" of 1 or more iterations, and at the end of that chunk, call setTimeout on a function that processes the next "chunk" of your loop, until eventually you reach the end. At the end of each "chunk" you update your progress dialog, and these updates appear in the DOM, prior to the setTimeout on the next "chunk".
The main problem with this is that you have to re-factor your code to use the continuation programming style, which does involve longer code that is more difficult to follow.
This may be successful for simple loops, but for a more complex process involving a pipeline of different operations, you have to design your code from the start to anticipate the continuation style of programming.
In some ways I quite like the continuation style, but none of my existing code fits it.
The other problem with this approach is that
setTimeout typically has a minimum time period of 4 to 15ms, which will impose a limit on loop speed. Of course as long as the user can see "progress" this may not be a major issue.
There is a solution I have been pointed to for zero setTimeout on non-IE browsers, if you need to optimise further. See David Baron's Blog. This involves using
postMessage back to the same window.
To be fair, if you are updating a progress bar, then zero timeout is probably the least of your worries, as the code involved in updating the display probably takes up a good chunk of processing time.
You will probably find in the end that Chrome is just about visible, but Opera is blinding.
Approach 6 : HTML5 Web Workers (WEIRD RESULTS - UNRELIABLE)
The basic idea is that you run your loop with a Worker, and send progress bar update messages back to the progress bar in your main page.
No good I am afraid.
- Only Opera and Firefox worked.
- Posting messages was very slow.
- Updating of the main window was patchy on Firefox.
- I did not like this solution as it generally required you to pack up your loop code in a separate js file for the worker to load.
- If you want to implement a stop button it requires you to adopt the continuation style of programming again, as you cannot pass a reference to an object in the main window, just a plain data type or JSON object. This means your worker has to give up time for the onmessage to process the stop.
Overall, not viable at the moment. I would welcome anyone else's views.
Approach 7 : HTML5 progress element
My last great hope was the Progress element.
Surely this was designed specifically for my problem?
No. At most it is a means of displaying progress, but it gives no guarantees as to how it will be updated.
In my particular test, only Opera worked as I would have hoped.
I think the progress element at the moment is a diaster of implementation.
Only IE gives me what I want.
setTimeout offers a cross-browser solution.
The new technologies of
progress are a disappointment of inconsistent implementation.
For all the ire and hatred thrown at Internet Explorer, it was my only friend in this area.
As a final point, why do browsers still require just
 for collections, when HTML5 clearly recognises
(): HTML Collection?