7 ответов:
что-то вроде этого:
$.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 } } });
один из подходов заключается в использовании функции-оболочки:
(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(лучше сухой)// 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') });точка, чтобы рассмотреть, что делает обязательно the
$.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 ); }); }
вот небольшой плагин для этого:
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, так как это в функции ошибки указывает на окно. (И этот способ использования "этого" недостаточно безопасен, поскольку вы не знаете, как они реализуют 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(){});использовать конструктор, чтобы убедиться, что запрос является реентерабельным!
ни один из этих ответов не работает, если кто-то звонит
.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 предложила добавить повторную попытку, так как это происходит для нас только один раз в голубой луне.
Comments