What's the Best Way to Retry an Ajax Request on Failure Using Jquery

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



Leave a reply



Submit