Kode semu:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Yang lebih baik lagi adalah semacam kemunduran eksponensial
Kode semu:
$(document).ajaxError(function(e, xhr, options, error) {
xhr.retry()
})
Yang lebih baik lagi adalah semacam kemunduran eksponensial
Jawaban:
Sesuatu seperti ini:
$.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
dilampirkan untuk memanggil fungsi yang mengembalikan permintaan ajax ini?
tryCount
dan retryLimit
berlebihan. Pertimbangkan untuk menggunakan hanya 1 variabel: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
properti di$.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
(lebih baik untuk KERING)// 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')
});
Hal yang perlu dipertimbangkan adalah memastikan bahwa $.ajax
metode tersebut belum digabungkan sebelumnya, untuk menghindari kode yang sama berjalan dua kali.
Anda dapat menyalin-tempel cuplikan ini (sebagaimana adanya) ke konsol untuk mengujinya
Saya telah banyak sukses dengan kode di bawah ini (contoh: 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 );
});
}
Tak satu pun dari jawaban ini berfungsi jika seseorang menelepon .done()
setelah panggilan ajax mereka karena Anda tidak akan memiliki metode yang berhasil untuk dilampirkan ke panggilan balik di masa mendatang. Jadi jika seseorang melakukan ini:
$.ajax({...someoptions...}).done(mySuccessFunc);
Maka mySuccessFunc
tidak akan dipanggil saat coba lagi. Inilah solusi saya, yang banyak dipinjam dari jawaban @ cjpak di sini . Dalam kasus saya, saya ingin mencoba lagi ketika AWS's API Gateway merespons dengan kesalahan 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);
});
Cuplikan ini akan mundur dan mencoba lagi setelah 2 detik, lalu 5 detik, lalu 10 detik, yang dapat Anda edit dengan mengubah konstanta RETRY_WAIT.
Dukungan AWS menyarankan agar kami menambahkan percobaan ulang, karena ini hanya terjadi sekali di bulan biru.
Berikut adalah plugin kecil untuk ini:
https://github.com/execjosh/jquery-ajax-retry
Batas waktu penambahan otomatis akan menjadi tambahan yang bagus untuk itu.
Untuk menggunakannya secara global cukup buat fungsi Anda sendiri dengan tanda tangan $ .ajax, gunakan di sana coba lagi api dan ganti semua panggilan $ .ajax Anda dengan fungsi baru Anda.
Anda juga dapat langsung mengganti $ .ajax, tetapi Anda tidak akan dapat melakukan panggilan xhr tanpa mencoba lagi.
Inilah metode yang berfungsi untuk saya untuk pemuatan pustaka asinkron:
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
});
}
}
Kemudian cukup panggil .load_script
dari aplikasi Anda dan tingkatkan panggilan balik sukses Anda:
$.loadScript('maps', '//maps.google.com/maps/api/js?v=3.23&libraries=geometry&libraries=places&language=&hl=®ion=', function(){
initialize_map();
loadListeners();
});
Jawaban DemoUsers tidak berfungsi dengan Zepto, karena ini dalam fungsi kesalahan mengarah ke Window. (Dan cara menggunakan 'ini' tidak cukup aman karena Anda tidak tahu bagaimana mereka mengimplementasikan ajax atau tidak perlu.)
Untuk Zepto, mungkin Anda bisa mencoba di bawah ini, sampai sekarang ini berfungsi dengan baik untuk saya:
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(){});
Gunakan konstruktor untuk memastikan permintaan reentrant!
Kode Anda hampir penuh :)
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
, dan jika gagal, Anda memanggil fungsi dengantries+1
. Hentikan eksekusi padatries==3
atau nomor lain.