使用jQuery重试失败的AJAX请求的最佳方法是什么?
伪代码:
$(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 } } });
我在下面的代码中取得了很大的成功(例如: 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 ); }); }
一种方法是使用包装函数:
(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);
另一种方法是在$.ajax
上使用retries
属性
// 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); }
另一种方式( GIST ) – 覆盖原来的$.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') });
需要考虑的一点是确保 $.ajax
方法以前不被包装,以避免相同的代码运行两次。
您可以将这些片段(按原样)复制粘贴到控制台以testing它们
这里是一个小插件:
https://github.com/execjosh/jquery-ajax-retry
自动递增超时将是一个很好的补充。
要全局使用它,只需使用$ .ajax签名来创build自己的函数,然后使用那里的重试API,并用新函数replace所有$ .ajax调用。
你也可以直接replace$ .ajax,但是如果没有重试,你将无法进行xhr调用。
以下是我用于asynchronous加载库的方法:
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
并嵌套您的成功callback:
$.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。 (这种使用'this'的方法不够安全,因为你不知道如何实现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(){});
使用构造函数来确保请求是可重入的!