41

i apologise if this is something i should be able to look up. all of the terms i wanted were way overloaded..

here is my problem: when i open a page, it fires off a whole series of ajax calls. if i then press Shift+Refresh, all of those ajax calls are being considered errors, and showing their error message dialogs before the entire page itself reloads.

so the error is being triggered by the client - is there anyway i can find out if this is the case so i can ignore it? eg in the xmlhttprequest, or in the ajax function (i am using jquery btw)

gcrain
  • 602
  • 2
  • 7
  • 17
  • You are putting the code inside an jQuery onLoad annonymous function right? Like, at the beginning of your code you have: $(function() { /* do all your ajax calls here */ }); You should wait until your DOM is loaded before doing ajax calls. – KyleFarris Mar 31 '09 at 13:36

5 Answers5

38

There are several suggested approaches for detecting this:

  • Several have suggested the use of a beforeunload handler to set a boolean flag so that the error handler can know that the page is being unloaded (See list of related/duplicated posts below). This is great, except that mobile Safari on iOS doesn't support the beforeunload event.

  • Sachindra suggested an approach where instead of firing the error function immediately, it got delayed a second in a setTimeout(..., 1000). That way, there is a good chance the page has actually disappeared by the time the error handler gets called. "Good chance" that is. I bet if I have a huge page with e.g. many <input>s, it could take more than 1 sec to unload, and then perhaps the error handler would fire anyway.

I therefore suggest a combination of reliably detecting beforeunload support and if beforeunload is not supported (cough iPad/iPhone cough) revert to Sachindra's delay trick.

See the full solution with beforeunload detection and all in this jsfiddle.

It looks like the situation is a little better for jQuery 2.x than for 1.x, but 2.x also seems a little flakey, and so I still find this suggestion prudent.

P.S: There were also suggestions involving testing some fields in the XHR / jqXHR object. (Here and here). I have not come accross a combination that could distinguish between user navigation and restarting the webserver during a long-running AJAX call, and I have therefore not found this approach useful to me.

This is really also an answer to these related/duplicated Stack Overflow questions:

and these posts outside of Stack Overflow:

Community
  • 1
  • 1
Peter V. Mørch
  • 13,830
  • 8
  • 69
  • 103
20

[this is an edit from the previous answer, which had outstanding questions that I have since resolved]

jQuery throws the error event when the user navigates away from the page either by refreshing, clicking a link, or changing the URL in the browser. You can detect these types of errors by by implementing an error handler for the ajax call, and inspecting the xmlHttpRequest object:

$.ajax({
    /* ajax options omitted */
    error: function (xmlHttpRequest, textStatus, errorThrown) {
         if(xmlHttpRequest.readyState == 0 || xmlHttpRequest.status == 0) 
              return;  // it's not really an error
         else
              // Do normal error handling
});
curthipster
  • 3,661
  • 3
  • 24
  • 18
  • 11
    This doesn't seem to work as advertised. When I introduce a "real error" by disabling my network connection during a long poll, I also see readyState == 0 and status == 0. – Wim Coenen Jun 13 '12 at 09:13
  • 6
    This does not work. This method stops detecting real errors too – Sachindra Mar 25 '13 at 20:01
  • 9
    Restarting the web server in the middle of a long poll also yields `readyState == 0 && status == 0`. This method is not reliable. – Peter V. Mørch Aug 05 '13 at 18:54
  • It doesn't work in Firefox. I get 404 error code and readyState has value 4 – broadband Oct 11 '17 at 07:21
6
var isPageBeingRefreshed = false;

window.onbeforeunload = function() {
    isPageBeingRefreshed = true;
};

$.ajax({
    error: function (xhr, type, errorThrown) {
        if (!xhr.getAllResponseHeaders()) {
            xhr.abort();
            if (isPageBeingRefreshed) {
                return; // not an error
            }
        }
    }
});
nisanth074
  • 131
  • 1
  • 6
  • 2
    This *almost* worked for me. It worked in Firefox, Chrome, IE8, IE10 and on Android's stock browser. [But **not** in iOS's Safari](http://stackoverflow.com/questions/4127621/is-there-any-way-to-use-window-onbeforeunload-on-mobile-safari-for-ios-devices). An improvement suggestion (that still doesn't work in Safari/iOS) would be to use `$(window).on('beforeunload', function () {...})` instead of `window.beforeunload = function () {...}` so as not to hijack/hog the beforeunload handler. Still looking for something that also works in iOS Safari too. – Peter V. Mørch Aug 05 '13 at 18:52
2

The above techniques does not work for a periodically refreshing page (for example every half seconds). I have figured out that the error caused by refreshing the page can be avoided using delaying the error handling process by a small amount of time.

Example:

$.ajax(...)
.success(...)
.error(function(jqXHR) {
setTimeout(function() {
  // error showing process
}, 1000);
});

In addition to that

window.onbeforeunload = function() {//stop ajax calls}

event can be used for less frequently refreshing ajax calls.

Sachindra
  • 2,052
  • 4
  • 23
  • 29
2

Combined version of nisanth074 and Peter V. Mørch answers, that worked for me.

Example:

var isPageBeingRefreshed = false;

$(window).on('beforeunload', function(){

    isPageBeingRefreshed = true;
});

$.ajax({

    // Standart AJAX settings

}).error(function(){

    if (!isPageBeingRefreshed) {

        // Displaying error message
    }
});
Vaidas
  • 968
  • 9
  • 22