Mã giả:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Thậm chí tốt hơn sẽ là một số loại dự phòng theo cấp số nhân
Mã giả:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Thậm chí tốt hơn sẽ là một số loại dự phòng theo cấp số nhân
Câu trả lời:
Một cái gì đó như thế này:
$.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
được đính kèm để gọi hàm trả về yêu cầu ajax này?
tryCount
và retryLimit
là quá mức. Xem xét sử dụng chỉ có 1 biến: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
tính trên$.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
(tốt hơn cho 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')
});
Một điểm cần xem xét là làm cho chắc chắn các $.ajax
phương pháp đã được chưa bọc trước đây, để tránh cùng mã chạy hai lần.
Bạn có thể sao chép và dán các đoạn mã này (nguyên trạng) vào bảng điều khiển để kiểm tra chúng
Tôi đã rất thành công với đoạn mã này bên dưới (ví dụ: 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 );
});
}
Không có câu trả lời nào trong số này hoạt động nếu ai đó gọi .done()
sau cuộc gọi ajax của họ vì bạn sẽ không có phương pháp thành công để đính kèm vào lần gọi lại trong tương lai. Vì vậy, nếu ai đó làm điều này:
$.ajax({...someoptions...}).done(mySuccessFunc);
Sau đó, mySuccessFunc
sẽ không được gọi khi thử lại. Đây là giải pháp của tôi, được vay mượn nhiều từ câu trả lời của @ cjpak ở đây . Trong trường hợp của tôi, tôi muốn thử lại khi API Gateway của AWS phản hồi với lỗi 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);
});
Đoạn mã này sẽ quay lại và thử lại sau 2 giây, sau đó 5 giây, rồi 10 giây, bạn có thể chỉnh sửa đoạn mã này bằng cách sửa đổi hằng số RETRY_WAIT.
Bộ phận hỗ trợ AWS đã đề xuất chúng tôi thêm một lần thử lại, vì nó chỉ xảy ra với chúng tôi một lần trong tuần trăng xanh.
Đây là một plugin nhỏ cho việc này:
https://github.com/execjosh/jquery-ajax-retry
Tự động tăng thời gian chờ sẽ là một bổ sung tốt cho nó.
Để sử dụng nó trên toàn cầu, chỉ cần tạo hàm của riêng bạn với chữ ký $ .ajax, sử dụng ở đó thử lại api và thay thế tất cả các lệnh gọi $ .ajax bằng hàm mới của bạn.
Ngoài ra, bạn có thể thay thế trực tiếp $ .ajax, nhưng bạn sẽ không thể thực hiện cuộc gọi xhr mà không thử lại sau đó.
Đây là phương pháp phù hợp với tôi để tải thư viện không đồng bộ:
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
});
}
}
Sau đó, chỉ cần gọi .load_script
từ ứng dụng của bạn và lồng cuộc gọi lại thành công của bạn:
$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=®ion=', function(){
initialize_map();
loadListeners();
});
Câu trả lời của DemoUsers không hoạt động với Zepto, vì điều này trong hàm lỗi đang trỏ đến Window. (Và cách sử dụng 'this' không đủ an toàn vì bạn không biết cách họ triển khai ajax hoặc không cần thiết.)
Đối với Zepto, có thể bạn có thể thử bên dưới, cho đến bây giờ nó hoạt động tốt đối với tôi:
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(){});
Sử dụng hàm tạo để đảm bảo yêu cầu được đưa vào lại!
Mã của bạn gần đầy :)
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
và nếu thất bại thì bạn gọi hàm của mình bằngtries+1
. Ngừng thực hiện trêntries==3
hoặc bất kỳ số nào khác.