Reputation: 4989
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
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
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