开发者

Timeouts on periodic ajax requests with jQuery

开发者 https://www.devze.com 2023-01-09 18:48 出处:网络
i use the following code to send an ajax-request every 3 seconds: var refreshId = setInterval(function() {

i use the following code to send an ajax-request every 3 seconds:

var refreshId = setInterval(function() {
    $.ajax({
        async: true,
        url: 'gohere',
        dataType: 'text',
        cache: false,
        timeout: 5000,

        success: function(result, textStatus, XMLHttpRequest) {
            alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
        },

        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
        }
    });
}, 3000);

The problem is, that even if the home-server is not accessible (eg not connected to the LAN) the success-function will be called instead of the error-function with a "timeout"-status (tested on Ubuntu 10.04 with FireFox 3.6.7).

开发者_StackOverflow社区 (Without periodic requests it will work fine: On timeouts the error-function is called with the correct 'timeout'-statusText.)

The success-alert-function will show the following text on timeouts:

    textStatus: success,
    XHR.readyState: 4,
    XHR.status: 0
So i need to use the XHR.status-value, which should be 200 on success, to determine errors. Is this the normal behaviour or did i something wrong?


ponder on moving the setTimeout in the success and error handlers instead and make it asynchronously recursive.

var refreshId = function() {
    $.ajax({
        async: true,
        url: 'gohere',
        dataType: 'text',
        cache: false,
        timeout: 5000,

        success: function(result, textStatus, XMLHttpRequest) {
            alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
            setTimeout(refreshId, 3000);
        },

        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
            setTimeout(refreshId, 3000);
        }
    });
};

Thing is, setTimeout and setInterval time is not reliable, especially with alerts. An alert call stalls javascript as long as the alert dialog remains open. Furthermore, setTimeout and setInterval do not interrupt currently running code to guarantee perfect timing, they will wait till the javascript thread has an opening and jump between code executions.

With your previous code setup, you also had a chance that the response of refreshId call 1 will arrive after refreshId call 2 due to the http roundtrip taking an undetermined ammount of time.

By making your setTimeout depend on the response comming in, you get a more stable and transparent result.


Well, messing around with asyncronous function callbacks can get messy :). setInterval() is one of those, so is .ajax().

You should try to use setTimeout() and just fire the next .ajax() call when the last has completed.

(function repeat(){
   $.ajax({
    async: true,
    url: 'gohere',
    dataType: 'text',
    cache: false,
    timeout: 5000,

    success: function(result, textStatus, XMLHttpRequest) {
        alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
    },

    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('textStatus: ' + textStatus + ",\nXHR.readyState: " + XMLHttpRequest.readyState + ",\nXHT.status: " + XMLHttpRequest.status);
    },

    complete: function(XMLHttpRequest){
       setTimeout(repeat, 3000);
    }
  });       
}());

If you are insistent to have an .ajax() as close as possible to 3 seconds, you can abort your last (possibly running) ajax request before fireing the new one.

Therefore, assign a variable to the return of .ajax() like

var currentxhr = $.ajax({});

and add a beforeSend callback into your .ajax() call. Within that handler call

currentxhr.abort();

That will abort a possibly running request.


Instead of looking at textStatus use this test: xhr.statusText.toUpperCase() === 'OK'

I ran into a problem with FF 3.6.8 having a xhr.status === 0 on 301 pages. I added the above to my jQuery 1.4.2 in the httpSuccess function:

return !xhr.status && location.protocol === "file:" ||
    // Opera returns 0 when status is 304
    ( xhr.status >= 200 && xhr.status < 300 ) ||
    xhr.status === 304 || xhr.status === 1223 ||
    ( xhr.status === 0 && xhr.statusText.toUpperCase() === 'OK');            


I believe you should look into http://plugins.jquery.com/project/ajaxqueue which is designed to manage ajax race conditions.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号