Reputation: 11391
I have all my ajax calls in a custom JS file. And trust me there are alot of them! I would like to implement a "retry on fail behavior" in all ajax calls.
Is there a way to do it like "interception"? Or do I have to do it one by one?
My fear here is that a future dev will forget to set the retry policy...
Sample ajax call:
$.ajax({
url: apiRoot + 'reservationItens?reservaId=' + idReservation + '&bagId=' + idBag,
type: 'PUT',
success: function () {
if (onSuccess != null) {
onSuccess();
}
},
error: function (x, y, z) {
if (onError != null) {
onError(x, y, z);
}
}
});
Upvotes: 1
Views: 9093
Reputation: 1506
Here's a working jsfiddle.
I'd do it like this, with a recursive function:
function AjaxRetry(settings, maxTries, interval) {
var self = this;
this.settings = settings;
this.maxTries = typeof maxTries === "number" ? maxTries : 0;
this.completedTries = 0;
this.interval = typeof interval === "number" ? interval : 0;
// Return a promise, so that you can chain methods
// as you would with regular jQuery ajax calls
return tryAjax().promise();
function tryAjax(deferred) {
console.log("Trying ajax #" + (self.completedTries + 1));
var d = deferred || $.Deferred();
$.ajax(self.settings)
.done(function(data) {
// If it succeeds, don't keep retrying
d.resolve(data);
})
.fail(function(error) {
self.completedTries++;
// Recursively call this function again (after a timeout)
// until either it succeeds or we hit the max number of tries
if (self.completedTries < self.maxTries) {
console.log("Waiting " + interval + "ms before retrying...");
setTimeout(function(){
tryAjax(d);
}, self.interval);
} else {
d.reject(error);
}
});
return d;
}
}
And then usage is like this:
var settings = {
url: "https://httpbin.org/get",
data: {foo: "bar"},
contentType: "application/json; charset=UTF-8"
};
var maxTries = 3;
var interval = 500;
// Make your ajax call and retry up to 3 times,
// waiting 500 milliseconds between attempts.
new AjaxRetry(settings, maxTries, interval)
.done(function(data){
alert("My ajax call succeeded!");
})
.fail(function(error) {
alert("My ajax call failed :'(");
})
.always(function(resp){
alert("My ajax call is over.");
});
Upvotes: 5
Reputation: 8520
You can use ajaxError
which takes a callback that is called on every ajax error.
Additionally you can add a boolean to the settings object and check for it in the callback which ensures that one failed request is only called a second time and not more.
$(document).ajaxError(function (event, jqxhr, settings) {
if(!settings.secondExec) {
settings.secondExec = true;
$.ajax(settings);
}
});
If desired add a timeout for the second request to increase the possibility that a random server or connection problem is resolved in the meantime:
setTimeout(function() {
$.ajax(settings);
}, 500);
If you want to exclude some requests just add another property to the request settings which you then use like secondExec
is used in the example.
Upvotes: 6
Reputation: 1881
You can create api method for ajax calls, just like this one. In the ajaxApi function you can create your own handlers. For example for success or error events, thanks to this developer using this api can attach his handlers, without worrying what else handlers to attach.
function outerSuccesFN() {
console.log('outerSuccesFN');
}
function outerErroFN() {
console.log('outerErroFN');
}
function completeFn() {
console.log(completeFn);
}
function ajaxApi(url, dataType, data, timeout) {
var ajaxResults = $.ajax({
url: url,
dataType: dataType,
data: data,
timeout: timeout
});
function mySuccesFn() {
console.log('mySuccesFn');
}
function myErroFn() {
console.log('myErroFn');
}
return ajaxResults.done(mySuccesFn).fail(myErroFn);
}
var ajaxResult = ajaxApi('http://api.jquery.com/jsonp/', 'jsonp', {
title: 'ajax'
}, 15000);
ajaxResult.done(outerSuccesFN).fail(outerErroFN).always(completeFn);
Upvotes: 4