13

What happens if I send some ajax request, and immediately change the page (say follow some link) before the request returns? I mean I suppose the XHR object sends a request to the website, but it is removed (since the page is changed) before the response is retrieved, so where should the response be sent to?

I am asking this question because I am having a strange problem with my website. I have a page that loads posts from the data store via an Ajax request. If before the load is complete I click on a link, I get the onerror of jQuery.ajax called! Not sure why that happens.

EDIT: This is my call to ajax. In the normal case, the success callback gets called. But when I click on a link, the error callback gets called! I am thinking about something, could it be because the data should be formatted as JSON, but the request is cut in the middle, so the data is considered invalid causing jQuery to call the error callback?! But then why the requests get cut in the middle?

$.ajax({
  type: (args.rel == "async" || args.rel == "dialog") ? "GET" : "POST",
  url: href,
  dataType: "json",
  data: args.data ? args.data:{}, // send {} to ensure Content-Length header
  success: function(data){
    if (context) context.removeClass("ajax_wait");
    if (args.hideonwait) $(args.hideonwait).show();
    if (args.showonwait) $(args.showonwait).hide();
    if (spinner) remove_spinner(context, spinner);
    handle_response(args, context, target, data);
  },
  error: function(xhr, status, errorThrown){
    if (context) context.removeClass("ajax_wait");
    if (args.hideonwait) $(args.hideonwait).show();
    if (args.showonwait) $(args.showonwait).hide();
    if (spinner) remove_spinner(context, spinner);
    ajax_error(args, context,
               status + "-" + xhr.status,
               errorThrown ? errorThrown : xhr.responseText);
  }
});
Rafid
  • 18,991
  • 23
  • 72
  • 108

5 Answers5

11

The trick is to check the response headers in the XMLHttpRequest object. If there are no response headers (null or empty string, depending on the browser), the server did not respond yet. That means the user aborted.

$.ajax({
    url: "url-to-go-here",
    success: function() {
    },
    error: function(xhr, textStatus, errorThrown) {
        if(!isUserAborted(xhr)) {
            console.log("Ajax Error")
        }
    }
});

function isUserAborted(xhr) {
  return !xhr.getAllResponseHeaders();
}

Source

Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
  • Only checking for `!xhr.getAllResponseHeaders()` may not work in all browsers. It can return an empty object even when there are no headers in the response, so you'll have to check for empty objects also. Otherwise, this works like a charm and should be accepted as the correct answer. – MarthyM Mar 31 '16 at 09:08
  • I've seen an answer elsewhere on the interwebs to check for `xhr.State() === "rejected"`. Is one method more valid than the next? – Daryl Dec 01 '16 at 20:26
3

The behavior seems to be when the user leaves a page, any outstanding ajax requests complete with 0 as their status. jQuery interprets this as an error, which is why it calls the error handler. In your error handler, you can call the same function that your success handler calls if xhr.status == 0, otherwise execute the desired error behavior.

mtalcott
  • 608
  • 1
  • 4
  • 11
1

The solution to this problem is simple, all you need to do is if the request is currently running and if the user clicks any other link, then you need to alert the user that the request is under process please wait

To achieve this you need to maintain a semaphore, set that semaphore before firing any request and reset it on completion of that request. On click of every link(which changes the page) call a method which checks the semaphore and if it is set then the method gives the above alert to the user. This way, until the request completes, the user wont be able to change the page, and your problem of request being aborted would be solved

Hope this answers the question.

naddy19
  • 304
  • 2
  • 12
0

I had to deal with the same issue few days ago .. seems like its not that complicated to deal with.. We should able to distinguish the weather its a ajax error of some sort or user abort the request.. of course we don't get specific event from xhr object .. that's why ajax error comes with an exception ...combination of both xhr object and exception value we can solve this.

var message = '';
$('whatever').ajaxError(function(e, xhr, settings, exception) {
  // logic
   if (!xhr.status){
      if (exception=='abort'){
         message = 'User aborted AJAX request !'; 
      }
   }
}
Prasad
  • 57
  • 5
0

You would be out of luck. You would have no callback to come back to. Ajax response would be lost. In this case I would put a blocker on the page. It's pretty common, in order to prevent another click. Blocker nothing more than big mask which "lays over" the entire browser. It could also have a wait icon.

ek_ny
  • 10,153
  • 6
  • 47
  • 60
  • That is the reasonable answer, but am I getting the onerror called?! If I don't change the page, the request works perfectly fine, so there is no reason for onerror to be called. – Rafid Aug 02 '11 at 10:03
  • Yeah.... I'm thinking about that now... this is an odd one. I wonder if the response comes back looking for it's callback.. but still one would think it would just "die". This is interesting-- can you replicate it with a very simple page? I would be curious. – ek_ny Aug 02 '11 at 10:06
  • @Promater I gave you an upvote on question-- it's interesting. Will look at it again in a bit. – ek_ny Aug 02 '11 at 10:16