coderz coderz - 3 months ago 63
Ajax Question

jQuery ajax - trigger fail callback function only when all retry failed

I use ajax with jQuery, as we know

$.ajax
return a promise
ajaxPromise
. My requirement is: only when all ajax call retries are failed,
ajaxPromise
catch the failure (I want to handle error within ajax promise callback function).

I tried following code:

function ajax(data) {
return $.ajax({
url: "...",
data: data,
triedCount: 0,
retryLimit: 3,
error: function(xhr, textStatus, errorThrown ) {
console.log("error: " + this.triedCount);
this.triedCount++;
if (this.triedCount < this.retryLimit) {
$.ajax(this);
}
}
});
}

var ajaxPromise = ajax({"id": "123"});
ajaxPromise.fail(function(xhr) {
console.log("All retries failed...");
// all retries failed, handle error
});


Output what I want is:

error: 0
error: 1
error: 2
All retries failed...


While actually the output is:

error: 0
All retries failed...
error: 1
error: 2


Looks like
fail
callback is triggered immediately after the first call fails, while I want
fail
callback triggered after all retries are failed.

Is there any way that only when all retries are failed then trigger
ajaxPromise.fail
callback? Or is there other options can do this?

Answer
function ajax(data) {
  return $.ajax({
    url: "...",
    data: data,
    triedCount: 0,
    retryLimit: 3,
    error: function(xhr, textStatus, errorThrown ) {
      console.log("error: " + this.triedCount);
      this.triedCount++;
      if (this.triedCount < this.retryLimit) {
        console.log(this);
        $.ajax(this);
      }
    }
  });
}

in your code here, you're calling the ajax function if an error occurred. but that doesn't mean the previous ajax call didn't complete. the first ajax call completes and send the return value(failure). your

ajaxPromise.fail(function(xhr) {
 console.log("All retries failed...");
  // all retries failed, handle error
});

runs, and you get "All retries failed..." is logged on to console. if you want to achieve what you want to achieve you'll have to intercept the previous result and prevent it from being returned. instead, check if 3 tries have been completed and then return the value. but i'm not sure how to do that.

EDIT: after long research i found it's just not possible. you should give up trying to do such a thing.. just kidding! check this code, i believe this is exactly what you want:

// Code goes here

function ajax(data) {
  var dfd = $.Deferred();
  $.ajax({
    url: "...",
    data: data,
    triedCount: 0,
    retryLimit: 3,
    success: function(){
      dfd.resolve("success");
    },
    error: function(xhr, textStatus, errorThrown ) {
      console.log("error: " + this.triedCount);
      this.triedCount++;
      if (this.triedCount < this.retryLimit) {
        $.ajax(this);
      }
      else{
        dfd.reject(xhr);
      }
    }
  });
  return dfd.promise();
}
var ajaxPromise = ajax({"id": "123"});
ajaxPromise.fail(function(xhr) {
  console.log("All retries failed...");
  // all retries failed, handle error
  console.log(xhr.responseText);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

EDIT: the error throws from the failed ajax call will be available in xhr parameter of ajaxPromise callback.