Javascript – Alternatives for Javascript Synchronous XMLHttpRequest (as timing out in Safari)

javascriptsafaritimeoutxmlhttprequest

Short version:
Looking for a method to wait for an Asynch XHR request or a way to get Synch XHR working in Safari.

Much longer version:
I'm working on a web service that uses various external data sources mashed together. I am using a Javacript front-end which makes AJAX/XHR calls to my PHP server code. There's no cross-site issues as the client only requests data from my server (the server makes the external data requests).

I'm using a synchronous XHR request as I have some post-load processing (sorting, filtering, etc) to do on the data before it is presented on screen.

This all works fine on IE, FF and Opera, but seems to be a problem to Safari (I haven't tried Chrome yet).

Using Firebug for Safari on my Windows machine I can see the server calling beng made and then it fails after a time above 10 seconds. On my iPad the message is slightly beter as it says: NETWORK_ERR: XMLHttpRequest Exception 101: A network error occurred in synchronous mode.

A bit of research indicates that Safari will timeout after 10 seconds in synch mode. There appears to be a timeout function which timeout function you can use to extend this (with a max limit for Safari of 60 seconds). Unfortunately I can't get this to work.

I'm now wondering what people would suggest as the best way of working around this through changes to the client Javacript code.

The two options I'm thinking are (i) find a working example of a synch XHR timeout that Safari browsers will honour; or (ii) having some sort of wrapper around an asynch XHR call so that the post-load processing waits for the load first.

I'm not a particulalry experienced Javascript hacker, but I have setup a fair amount on this project. I haven't used JQuery or any other frameworks and would prefer to keep with raw JS just to avoid having to learn the additional syntax. [You may see from my previous posts I tried using JQM and Spry in the past, but both proved to be the wrong choices, at least at this stage and have since been ditched for now].

I get the feeling a callback may be the right wait-for-asych option, but I'm not sure how this works or how you would code it.

This is just a prototype at this stage, so dirty hacks are acceptable. A full re-write is already on the cards for later on once I have proven functionality.

Appreciate peoples thoughts and advice on this.

Regards,
Pete.

Best Answer

Generally, you'll want to stick to asynchronous requests, as they're non-blocking. And with them, you'll want to use a callback -- or, simply, a function that is setup to be called later.

You can set the callback with the onreadystatechange property of an XMLHttpRequest:

xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {   // DONE
        if (xhr.status === 200) { // OK
            handleSuccess(xhr);
        } else {
            handleError(xhr);
        }
    }
};

As the property name suggests, it will be called as the value of readyState changes, where a value of 4 means the request has completed (successful or not).

You'd then handle your sorting, filtering, etc. within another function -- in this example, handleSuccess.

You can also benefit from using any of a number of existing libraries -- e.g., jQuery (1.6 or later for this snippet):

$.get('/web/service/request')
    .done(function (result) {
        // sorting, filtering, etc
    })
    .fail(function (xhr) {
        // error notification, etc.
    });