Pseudocode:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Noch besser wäre eine Art exponentieller Rückzieher
Pseudocode:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Noch besser wäre eine Art exponentieller Rückzieher
Antworten:
Etwas wie das:
$.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
}
}
});
.success
der Aufruf der Funktion, die diese Ajax-Anforderung zurückgibt, angehängt ist?
tryCount
und retryLimit
ist übertrieben. Verwenden Sie nur 1 Variable:this.retryLimit--; if (this.retryLimit) { ... $.ajax(this) ... }
(function runAjax(retries, delay){
delay = delay || 1000;
$.ajax({
type : 'GET',
url : '',
dataType : 'json',
contentType : 'application/json'
})
.fail(function(){
console.log(retries); // prrint retry count
retries > 0 && setTimeout(function(){
runAjax(--retries);
},delay);
})
})(3, 100);
retries
Eigenschaft auf dem$.ajax
// define ajax settings
var ajaxSettings = {
type : 'GET',
url : '',
dataType : 'json',
contentType : 'application/json',
retries : 3 // <-----------------------
};
// run initial ajax
$.ajax(ajaxSettings).fail(onFail)
// on fail, retry by creating a new Ajax deferred
function onFail(){
if( ajaxSettings.retries-- > 0 )
setTimeout(function(){
$.ajax(ajaxSettings).fail(onFail);
}, 1000);
}
$.ajax
(besser für DRY)// enhance the original "$.ajax" with a retry mechanism
$.ajax = (($oldAjax) => {
// on fail, retry by creating a new Ajax deferred
function check(a,b,c){
var shouldRetry = b != 'success' && b != 'parsererror';
if( shouldRetry && --this.retries > 0 )
setTimeout(() => { $.ajax(this) }, this.retryInterval || 100);
}
return settings => $oldAjax(settings).always(check)
})($.ajax);
// now we can use the "retries" property if we need to retry on fail
$.ajax({
type : 'GET',
url : 'http://www.whatever123.gov',
timeout : 2000,
retries : 3, // <-------- Optional
retryInterval : 2000 // <-------- Optional
})
// Problem: "fail" will only be called once, and not for each retry
.fail(()=>{
console.log('failed')
});
Ein zu berücksichtigender Punkt ist, sicherzustellen , dass die $.ajax
Methode noch nicht zuvor umbrochen wurde, um zu vermeiden, dass derselbe Code zweimal ausgeführt wird.
Sie können diese Snippets (wie sie sind) kopieren und in die Konsole einfügen, um sie zu testen
Ich habe mit diesem Code unten viel Erfolg gehabt (Beispiel: http://jsfiddle.net/uZSFK/ )
$.ajaxSetup({
timeout: 3000,
retryAfter:7000
});
function func( param ){
$.ajax( 'http://www.example.com/' )
.success( function() {
console.log( 'Ajax request worked' );
})
.error(function() {
console.log( 'Ajax request failed...' );
setTimeout ( function(){ func( param ) }, $.ajaxSetup().retryAfter );
});
}
Keine dieser Antworten funktioniert, wenn jemand .done()
nach seinem Ajax-Anruf anruft , da Sie nicht über die Erfolgsmethode verfügen, die Sie an den zukünftigen Rückruf anhängen können. Also, wenn jemand dies tut:
$.ajax({...someoptions...}).done(mySuccessFunc);
Dann mySuccessFunc
wird der Wiederholungsversuch nicht aufgerufen. Hier ist meine Lösung, die stark von der Antwort von @ cjpak hier entlehnt ist . In meinem Fall möchte ich es erneut versuchen, wenn das API-Gateway von AWS mit einem 502-Fehler antwortet.
const RETRY_WAIT = [10 * 1000, 5 * 1000, 2 * 1000];
// This is what tells JQuery to retry $.ajax requests
// Ideas for this borrowed from https://stackoverflow.com/a/12446363/491553
$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
if(opts.retryCount === undefined) {
opts.retryCount = 3;
}
// Our own deferred object to handle done/fail callbacks
let dfd = $.Deferred();
// If the request works, return normally
jqXHR.done(dfd.resolve);
// If the request fails, retry a few times, yet still resolve
jqXHR.fail((xhr, textStatus, errorThrown) => {
console.log("Caught error: " + JSON.stringify(xhr) + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown);
if (xhr && xhr.readyState === 0 && xhr.status === 0 && xhr.statusText === "error") {
// API Gateway gave up. Let's retry.
if (opts.retryCount-- > 0) {
let retryWait = RETRY_WAIT[opts.retryCount];
console.log("Retrying after waiting " + retryWait + " ms...");
setTimeout(() => {
// Retry with a copied originalOpts with retryCount.
let newOpts = $.extend({}, originalOpts, {
retryCount: opts.retryCount
});
$.ajax(newOpts).done(dfd.resolve);
}, retryWait);
} else {
alert("Cannot reach the server. Please check your internet connection and then try again.");
}
} else {
defaultFailFunction(xhr, textStatus, errorThrown); // or you could call dfd.reject if your users call $.ajax().fail()
}
});
// NOW override the jqXHR's promise functions with our deferred
return dfd.promise(jqXHR);
});
Dieses Snippet wird nach 2 Sekunden, dann nach 5 Sekunden und nach 10 Sekunden zurückgesetzt und erneut versucht. Sie können es bearbeiten, indem Sie die Konstante RETRY_WAIT ändern.
Der AWS-Support schlug vor, einen erneuten Versuch hinzuzufügen, da dies bei einem blauen Mond nur einmal vorkommt.
Hier ist ein kleines Plugin dafür:
https://github.com/execjosh/jquery-ajax-retry
Das Zeitlimit für die automatische Inkrementierung wäre eine gute Ergänzung.
Um es global zu verwenden, erstellen Sie einfach Ihre eigene Funktion mit der Signatur $ .ajax, verwenden Sie dort die Wiederholungs-API und ersetzen Sie alle Ihre $ .ajax-Aufrufe durch Ihre neue Funktion.
Sie könnten auch $ .ajax direkt ersetzen, aber Sie können dann keine xhr-Aufrufe tätigen, ohne es erneut zu versuchen.
Hier ist die Methode, die für mich beim asynchronen Laden von Bibliotheken funktioniert hat:
var jqOnError = function(xhr, textStatus, errorThrown ) {
if (typeof this.tryCount !== "number") {
this.tryCount = 1;
}
if (textStatus === 'timeout') {
if (this.tryCount < 3) { /* hardcoded number */
this.tryCount++;
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status === 500) {
//handle error
} else {
//handle error
}
};
jQuery.loadScript = function (name, url, callback) {
if(jQuery[name]){
callback;
} else {
jQuery.ajax({
name: name,
url: url,
dataType: 'script',
success: callback,
async: true,
timeout: 5000, /* hardcoded number (5 sec) */
error : jqOnError
});
}
}
Rufen .load_script
Sie dann einfach von Ihrer App aus an und verschachteln Sie Ihren Erfolgsrückruf:
$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=®ion=', function(){
initialize_map();
loadListeners();
});
Die Antwort von DemoUsers funktioniert nicht mit Zepto, da dies in der Fehlerfunktion auf Window zeigt. (Und diese Art der Verwendung von 'this' ist nicht sicher genug, da Sie nicht wissen, wie sie Ajax implementieren oder nicht müssen.)
Für Zepto könnten Sie es vielleicht unten versuchen, bis jetzt funktioniert es gut für mich:
var AjaxRetry = function(retryLimit) {
this.retryLimit = typeof retryLimit === 'number' ? retryLimit : 0;
this.tryCount = 0;
this.params = null;
};
AjaxRetry.prototype.request = function(params, errorCallback) {
this.tryCount = 0;
var self = this;
params.error = function(xhr, textStatus, error) {
if (textStatus === 'timeout') {
self.tryCount ++;
if (self.tryCount <= self.retryLimit) {
$.ajax(self.params)
return;
}
}
errorCallback && errorCallback(xhr, textStatus, error);
};
this.params = params;
$.ajax(this.params);
};
//send an ajax request
new AjaxRetry(2).request(params, function(){});
Verwenden Sie den Konstruktor, um sicherzustellen, dass die Anforderung erneut eingegeben wird!
Dein Code ist fast voll :)
const counter = 0;
$(document).ajaxSuccess(function ( event, xhr, settings ) {
counter = 0;
}).ajaxError(function ( event, jqxhr, settings, thrownError ) {
if (counter === 0 /*any thing else you want to check ie && jqxhr.status === 401*/) {
++counter;
$.ajax(settings);
}
});
tries
, und wenn dies fehlschlägt, rufen Sie Ihre Funktion mit auftries+1
. Beenden Sie die Ausführung auftries==3
oder einer anderen Nummer.