What's the best way to retry an AJAX request on failure using jQuery?
Something like this:
$.ajax({
url : 'someurl',
type : 'POST',
data : ....,
tryCount : 0,
retryLimit : 3,
success : function(json) {
//do something
},
error : function(xhr, textStatus, errorThrown ) {
if (textStatus == 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status == 500) {
//handle error
} else {
//handle error
}
}
});
Retry ajax call until successful
That link you posted contains the exact answer ... you just need to wrap your code in a function so it can be used recursively:
function myAjaxRequest () {
$.ajax({
url: "<%= my_ruby_on_rails_controller_url_here %>",
datatype: "json",
type: "GET",
success: function (json) {
document.getElementById("factureload" + json.hashed_id).innerHTML = "<a href='" + json.address + "'><img class='pdficonstyling' src='/assets/pdf4.svg' alt='pdf icon' /> facture_" + json.numfacture + "</a>";
},
error: function () {
setTimeout(() => {
myAjaxRequest()
}, 5000) // if there was an error, wait 5 seconds and re-run the function
}
})
}
myAjaxRequest()
Retry failed jQuery.ajax requests
I think your code is the right way to do it, wrap your call in a new Deferred and return it until all attempts are reached.
You could try to include your recursive call inside a anonymous function to improve readibility maybe.
I wrote it like that :
function doAjax(ajaxArgs, attempt) {
// the wrapped returned dfd
var wrappedDfd = $.Deferred();
// your nested call using attempt counter
(function nestedCall() {
// if call succed, resolve the wrapped dfd
$.ajax(ajaxArgs).then(wrappedDfd.resolve, function() {
// update attempt counter
attempt--;
if (attempt > 0) {
// try another call
nestedCall();
} else {
// max try reached, reject wrapped dfd
wrappedDfd.reject();
}
});
})();
return wrappedDfd.promise();
};
which is really similar to your code.
Here is the jsfiddle. For test purpose, I replaced doAjax arguments by a mock factory call, but the code stay the same.
Hope this help.
Retry a jquery ajax request which has callbacks attached to its deferred
You could use jQuery.ajaxPrefilter
to wrap the jqXHR in another deferred object.
I made an example on jsFiddle
that shows it working, and tried to adapt some of your code to handle the 401 into this version:
$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
// you could pass this option in on a "retry" so that it doesn't
// get all recursive on you.
if (opts.refreshRequest) {
return;
}
// our own deferred object to handle done/fail callbacks
var dfd = $.Deferred();
// if the request works, return normally
jqXHR.done(dfd.resolve);
// if the request fails, do something else
// yet still resolve
jqXHR.fail(function() {
var args = Array.prototype.slice.call(arguments);
if (jqXHR.status === 401) {
$.ajax({
url: '/refresh',
refreshRequest: true,
error: function() {
// session can't be saved
alert('Your session has expired. Sorry.');
// reject with the original 401 data
dfd.rejectWith(jqXHR, args);
},
success: function() {
// retry with a copied originalOpts with refreshRequest.
var newOpts = $.extend({}, originalOpts, {
refreshRequest: true
});
// pass this one on to our deferred pass or fail.
$.ajax(newOpts).then(dfd.resolve, dfd.reject);
}
});
} else {
dfd.rejectWith(jqXHR, args);
}
});
// NOW override the jqXHR's promise functions with our deferred
return dfd.promise(jqXHR);
});
This works because deferred.promise(object)
will actually overwrite all of the "promise methods" on the jqXHR.
NOTE: To anyone else finding this, if you are attaching callbacks with success:
and error:
in the ajax options, this snippet will not work the way you expect. It assumes that the only callbacks are the ones attached using the .done(callback)
and .fail(callback)
methods of the jqXHR.
Configure jQuery to retry ajax calls if they fail
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);
Configure jQuery to retry ajax calls if they fail
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);
jQuery ajaxSetup, cannot retry ajax call into error handling
You could put your request inside a function then call it inside the callback again like :
function myRequest(){
$.ajax({
url: _url
//async: false,
type: 'POST'
}).success(function(jsonP) {
// ...
}).error(
// ...
);
}
myRequest();
$.ajaxSetup({
tryCount: 0,
retryLimit: 2,
error: function(xhr, textStatus, errorThrown) {
if (xhr.status == 401 && (JSON.parse(localStorage.getItem('Auth')).user[0] != null)) {
refreshToken();
this.tryCount++;
setTimeout(function() {
console.log(xhr);
if (this.tryCount <= this.retryLimit) { // this.tryCount is undefined
//try again
myRequest();
$('#loading-modal').modal('hide');
return;
} else {
alert("Problème de connexion");
return false;
}
}, 1000);
return;
} else {
/* alert("Problème d'authentification");
$(".logout").trigger('click'); */
}
if (xhr.status == 500) {
//handle error
} else {
//handle error
}
}
});
JavaScript: Add delay to a jquery ajax retry
The context of this
has changed by the time that retry()
function executes, and is no longer the AJAX info. You should, however, be able to wrap it in a closure by using a variable:
var self = this;
var retry = function () {
$.ajax(self);
};
(Note that this whole context is itself also happening in a callback, error
. So if this
still isn't what you need it to be, you may need to apply this same concept another scope higher.)
How do I resend a failed ajax request?
Found this post that suggests a good solution to this problem.
The main thing is to use $.ajaxPrefilter and replace your error handler with a custom one that checks for retries and performs a retry by using the closure's 'originalOptions'.
I'm posting the code just in case it will be offline in the future. Again, the credit belongs to the original author.
// register AJAX prefilter : options, original options
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
originalOptions._error = originalOptions.error;
// overwrite error handler for current request
options.error = function( _jqXHR, _textStatus, _errorThrown ){
if (... it should not retry ...){
if( originalOptions._error ) originalOptions._error( _jqXHR, _textStatus, _errorThrown );
return;
};
// else... Call AJAX again with original options
$.ajax( originalOptions);
};
});
Related Topics
JavaScript Syntax (0, Fn)(Args)
Failed to Load C++ Bson Extension
Url Encode a String in Jquery for an Ajax Request
Does JavaScript Support 64-Bit Integers
How Does Shallow Compare Work in React
Create a String of Variable Length, Filled with a Repeated Character
JavaScript in <Head> or Just Before </Body>
Convert Td Columns into Tr Rows
How to Make a Button Redirect My Page to Another Page
Angular2:Render a Component Without Its Wrapping Tag
Check If Event Is Triggered by a Human
What the Difference of This.State and This.Setstate in Reactjs
Add St, Nd, Rd and Th (Ordinal) Suffix to a Number
How to Send Variables from One File to Another in JavaScript
Prevent Orientation Change in iOS Safari
Where Should I Declare JavaScript Files Used in My Page? in <Head></Head> or Near </Body>