Skip to content

Stop the browser “throbber of doom” while loading comet/server push XMLHttpRequest

(This question is similar to this one, but it’s for using XMLHttpRequest instead of an iframe for Comet.)

I’m starting an async long poll like this:

var xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.send();

If I do this inside <script>...</script> in the head, it will cause the document to keep loading forever. (I’m testing this in Safari on Mac OS X and the iPhone, and it’s the only browser I need to support).

Using DOMContentLoaded or load events won’t work.

Using a setTimeout with a large enough delay will work. 0 won’t, 1000 will, 100 will some times and not other times. I don’t feel comfortable with this.

The only way I found that works is the combination of both:

document.addEventListener('DOMContentLoaded', function () {
    setTimeout(function () {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url);
        xhr.send();
    }, 0);
});

I guess this solves the problem for now, but I’m still afraid it will break in the future. // Edit: this doesn’t work reliably either.

Does anyone know of a more reliable way?

Answer

I’m not sure, but it seems that if the browser shows that it’s still downloading then that’s entirely correct – isn’t that basically what Comet programming is? The server is still sending unbuffered content and when that streams in a block of javascript it’s executed, allowing the server to push events to the client browser.

In the Ajax early days (for instance on IE6 where XMLHttpRequest was a separate ActiveX object) I’d of expected the browser to not know that it was still waiting.

But in Safari 4, Chrome, FX3.5 and all the modern browsers the XMLHttpRequest is built in – it knows that it’s still waiting for the server to still stream its content, exactly as it would with and <IFrame>

In short – I’d expect any Comet approach to show that the browser was still downloading because it is. I’d expect any workaround you find to get fixed in future builds because Comet is essentially a hack to get a server-push model working.

However they have started to built real server-push support into HTML 5.

Does mobile Webkit support the HTML 5 draft event-source tag yet? If so you could potentially try that.

Then you would have something like this:

<!-- new HTML 5 tag supporting server-push -->
<event-source src="http://myPushService.com" id="service">

<script type="text/javascript">

    function handleServiceEvent(event) {
        // do stuff
    }

    // tell browser to fire handleServiceEvent in response to server-push
    document.getElementById('service').addEventListener('event name', handleServiceEvent, false);
</script>