coderz
coderz

Reputation: 4989

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?

Upvotes: 0

Views: 1443

Answers (2)

Mridul Kashyap
Mridul Kashyap

Reputation: 700

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.

Upvotes: 1

guest271314
guest271314

Reputation: 1

You can use $.Deferred(), .rejectWith(); call a recursive function with beforeStart of $.Deferred() with ajaxOptions passed as parameter; if this.triedCount is not less than this.retryLimit, return rejected deferred object with this set to current ajax options, xhr passed as parameter to .fail() chained to ajaxPromise

function ajax(data) {
  var ajaxOptions = {
    url: "...",
    data: data,
    triedCount: 0,
    retryLimit: 3
  };
  return new $.Deferred(function(dfd) {
    function request(opts) {
      $.ajax(opts)
        .fail(function(xhr, textStatus, errorThrown) {
          console.log("error: " + this.triedCount);
          this.triedCount++;
          if (this.triedCount < this.retryLimit) {
            return request(this)
          } else {
            dfd.rejectWith(this, [xhr])
          }
        })
    }
    request(ajaxOptions)
  })
}

var ajaxPromise = ajax({
  "id": "123"
});
ajaxPromise.fail(function(xhr) {
  console.log("All retries failed...", xhr);
  // all retries failed, handle error
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>

Upvotes: 2

Related Questions