Псевдокод:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Ще краще було б якесь експоненціальне відступлення
Псевдокод:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Ще краще було б якесь експоненціальне відступлення
Відповіді:
Щось на зразок цього:
$.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
приєднаний до виклику функції, яка повертає цей запит ajax?
tryCount
і retryLimit
надмірна. Подумайте про використання лише 1 змінної: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
власності на$.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
(краще для 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')
});
Важливим моментом є переконання, що $.ajax
метод не був завершений раніше, щоб уникнути того самого коду, який працює два рази.
Ви можете скопіювати і вставити ці фрагменти (як є) на консоль, щоб перевірити їх
Я мав багато успіху з цим кодом нижче (приклад: 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 );
});
}
Жоден із цих відповідей не спрацьовує, якщо хтось дзвонить .done()
після їх дзвінка Ajax, оскільки у вас не буде способу успіху, щоб приєднатися до майбутнього зворотного дзвінка. Тож якщо хтось це робить:
$.ajax({...someoptions...}).done(mySuccessFunc);
Тоді mySuccessFunc
не буде викликано повторного спроби. Ось моє рішення, яке сильно запозичено з відповіді @ cjpak тут . У моєму випадку я хочу повторити спробу, коли API-шлюз AWS відповідає на помилку 502.
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);
});
Цей фрагмент відключиться та повториться через 2 секунди, потім 5 секунд, потім 10 секунд, які ви можете відредагувати, змінивши константу RETRY_WAIT.
Підтримка AWS запропонувала нам додати повторного спроби, оскільки це трапляється для нас лише раз у синій місяць.
Ось невеликий плагін для цього:
https://github.com/execjosh/jquery-ajax-retry
Авто час збільшення тайм-ауту було б хорошим доповненням до нього.
Щоб використовувати його в усьому світі, просто створіть власну функцію з підписом $ .ajax, використовуйте там повторний api та замініть всі ваші виклики $ .ajax на нову функцію.
Також ви можете безпосередньо замінити $ .ajax, але ви не зможете робити дзвінки xhr без повторного спроби.
Ось метод, який працював для мене для асинхронного завантаження бібліотек:
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
});
}
}
Тоді просто зателефонуйте .load_script
зі свого додатка та вставте зворотний дзвінок успіху:
$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=®ion=', function(){
initialize_map();
loadListeners();
});
Відповідь DemoUsers не працює з Zepto, оскільки ця функція помилки вказує на Window. (І спосіб використання "цього" недостатньо безпечний, оскільки ви не знаєте, як вони реалізують ajax або не потрібно.)
Для Zepto, можливо, ви можете спробувати нижче, до цих пір це добре працює для мене:
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(){});
Скористайтеся конструктором, щоб переконатися, що запит наданий!
Ваш код майже повний :)
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
, а в разі невдачі ви подзвоните свою функціюtries+1
. Зупинити виконання наtries==3
або будь-якому іншому номері.