J'ai un problème lorsque toutes les demandes ajax actives échouent lors de la soumission d'un formulaire, ce qui déclenche un événement d'erreur.
Comment arrêter toutes les requêtes ajax actives dans jQuery sans déclencher un événement d'erreur?
Chaque fois que vous créez une demande ajax, vous pouvez utiliser une variable pour la stocker:
var request = $.ajax({
type: 'POST',
url: 'someurl',
success: function(result){}
});
Ensuite, vous pouvez abandonner la demande:
request.abort();
Vous pouvez utiliser un tableau gardant une trace de toutes les demandes ajax en attente et les abandonner si nécessaire.
L'extrait suivant vous permet de gérer une liste (pool) de demandes et de les annuler si nécessaire. Il est préférable de placer dans le <HEAD>
de votre code HTML, avant tous les autres appels AJAX sont passés.
<script type="text/javascript">
$(function() {
$.xhrPool = [];
$.xhrPool.abortAll = function() {
$(this).each(function(i, jqXHR) { // cycle through list of recorded connection
jqXHR.abort(); // aborts connection
$.xhrPool.splice(i, 1); // removes from list by index
});
}
$.ajaxSetup({
beforeSend: function(jqXHR) { $.xhrPool.Push(jqXHR); }, // annd connection to list
complete: function(jqXHR) {
var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
}
});
})
</script>
Utiliser ajaxSetup n’est pas correct, comme indiqué sur sa page de documentation. Il ne configure que les valeurs par défaut et si certaines demandes les remplacent, il y aura un désordre.
Je suis bien en retard pour la fête, mais juste pour une référence future si quelqu'un cherche une solution au même problème, voici mon essai, inspiré par et largement identique aux réponses précédentes, mais plus complet
// Automatically cancel unfinished ajax requests
// when the user navigates elsewhere.
(function($) {
var xhrPool = [];
$(document).ajaxSend(function(e, jqXHR, options){
xhrPool.Push(jqXHR);
});
$(document).ajaxComplete(function(e, jqXHR, options) {
xhrPool = $.grep(xhrPool, function(x){return x!=jqXHR});
});
var abort = function() {
$.each(xhrPool, function(idx, jqXHR) {
jqXHR.abort();
});
};
var oldbeforeunload = window.onbeforeunload;
window.onbeforeunload = function() {
var r = oldbeforeunload ? oldbeforeunload() : undefined;
if (r == undefined) {
// only cancel requests if there is no Prompt to stay on the page
// if there is a Prompt, it will likely give the requests enough time to finish
abort();
}
return r;
}
})(jQuery);
Voici ce que j'utilise actuellement pour y parvenir.
$.xhrPool = [];
$.xhrPool.abortAll = function() {
_.each(this, function(jqXHR) {
jqXHR.abort();
});
};
$.ajaxSetup({
beforeSend: function(jqXHR) {
$.xhrPool.Push(jqXHR);
}
});
Remarque: chaque fichier underscore.js est présent, mais évidemment pas nécessaire. Je suis juste paresseux et je ne veux pas le changer en $ .each (). 8P
Attribuez à chaque demande xhr un identifiant unique et stockez la référence de l'objet dans un objet avant de l'envoyer. Supprimez la référence à la fin d'une demande xhr.
Pour annuler toute demande à tout moment:
$.ajaxQ.abortAll();
Renvoie les identifiants uniques de la demande annulée. Seulement à des fins de test.
Fonction de travail:
$.ajaxQ = (function(){
var id = 0, Q = {};
$(document).ajaxSend(function(e, jqx){
jqx._id = ++id;
Q[jqx._id] = jqx;
});
$(document).ajaxComplete(function(e, jqx){
delete Q[jqx._id];
});
return {
abortAll: function(){
var r = [];
$.each(Q, function(i, jqx){
r.Push(jqx._id);
jqx.abort();
});
return r;
}
};
})();
Retourne un objet avec une seule fonction qui peut être utilisé pour ajouter plus de fonctionnalités si nécessaire.
Je l'ai trouvé trop facile pour plusieurs demandes.
step1: définir une variable en haut de page:
xhrPool = []; // no need to use **var**
step2: set beforeSend dans toutes les requêtes ajax:
$.ajax({
...
beforeSend: function (jqXHR, settings) {
xhrPool.Push(jqXHR);
},
...
step3: utilisez-le où vous le souhaitez:
$.each(xhrPool, function(idx, jqXHR) {
jqXHR.abort();
});
J'ai étendu la réponse mkmurray et SpYk3HH ci-dessus afin que xhrPool.abortAll puisse abandonner toutes les demandes en attente d'une URL donnée:
$.xhrPool = [];
$.xhrPool.abortAll = function(url) {
$(this).each(function(i, jqXHR) { // cycle through list of recorded connection
console.log('xhrPool.abortAll ' + jqXHR.requestURL);
if (!url || url === jqXHR.requestURL) {
jqXHR.abort(); // aborts connection
$.xhrPool.splice(i, 1); // removes from list by index
}
});
};
$.ajaxSetup({
beforeSend: function(jqXHR) {
$.xhrPool.Push(jqXHR); // add connection to list
},
complete: function(jqXHR) {
var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
}
});
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
console.log('ajaxPrefilter ' + options.url);
jqXHR.requestURL = options.url;
});
L'utilisation est la même, sauf que abortAll peut maintenant éventuellement accepter une URL en tant que paramètre et annule uniquement les appels en attente à cette URL.
Le code de Andy m'a posé quelques problèmes, mais il m'a donné d'excellentes idées. Le premier problème était que nous devrions supprimer tous les objets jqXHR qui se terminent avec succès. J'ai également dû modifier la fonction abortAll. Voici mon code de travail final:
$.xhrPool = [];
$.xhrPool.abortAll = function() {
$(this).each(function(idx, jqXHR) {
jqXHR.abort();
});
};
$.ajaxSetup({
beforeSend: function(jqXHR) {
$.xhrPool.Push(jqXHR);
}
});
$(document).ajaxComplete(function() {
$.xhrPool.pop();
});
Je n'aimais pas la façon dont ajaxComplete () faisait les choses. Peu importe comment j'ai essayé de configurer .ajaxSetup cela n'a pas fonctionné.
J'ai mis à jour le code pour qu'il fonctionne pour moi
$.xhrPool = [];
$.xhrPool.abortAll = function() {
$(this).each(function(idx, jqXHR) {
jqXHR.abort();
});
$(this).each(function(idx, jqXHR) {
var index = $.inArray(jqXHR, $.xhrPool);
if (index > -1) {
$.xhrPool.splice(index, 1);
}
});
};
$.ajaxSetup({
beforeSend: function(jqXHR) {
$.xhrPool.Push(jqXHR);
},
complete: function(jqXHR) {
var index = $.inArray(jqXHR, $.xhrPool);
if (index > -1) {
$.xhrPool.splice(index, 1);
}
}
});
Jeter mon chapeau. Offre les méthodes abort
et remove
contre le tableau xhrPool
et n'est pas sujet aux problèmes de ajaxSetup
.
/**
* Ajax Request Pool
*
* @author Oliver Nassar <[email protected]>
* @see http://stackoverflow.com/questions/1802936/stop-all-active-ajax-requests-in-jquery
*/
jQuery.xhrPool = [];
/**
* jQuery.xhrPool.abortAll
*
* Retrieves all the outbound requests from the array (since the array is going
* to be modified as requests are aborted), and then loops over each of them to
* perform the abortion. Doing so will trigger the ajaxComplete event against
* the document, which will remove the request from the pool-array.
*
* @access public
* @return void
*/
jQuery.xhrPool.abortAll = function() {
var requests = [];
for (var index in this) {
if (isFinite(index) === true) {
requests.Push(this[index]);
}
}
for (index in requests) {
requests[index].abort();
}
};
/**
* jQuery.xhrPool.remove
*
* Loops over the requests, removes it once (and if) found, and then breaks out
* of the loop (since nothing else to do).
*
* @access public
* @param Object jqXHR
* @return void
*/
jQuery.xhrPool.remove = function(jqXHR) {
for (var index in this) {
if (this[index] === jqXHR) {
jQuery.xhrPool.splice(index, 1);
break;
}
}
};
/**
* Below events are attached to the document rather than defined the ajaxSetup
* to prevent possibly being overridden elsewhere (presumably by accident).
*/
$(document).ajaxSend(function(event, jqXHR, options) {
jQuery.xhrPool.Push(jqXHR);
});
$(document).ajaxComplete(function(event, jqXHR, options) {
jQuery.xhrPool.remove(jqXHR);
});
Faites un pool de toutes les requêtes ajax et abandonnez-les .....
var xhrQueue = [];
$(document).ajaxSend(function(event,jqxhr,settings){
xhrQueue.Push(jqxhr); //alert(settings.url);
});
$(document).ajaxComplete(function(event,jqxhr,settings){
var i;
if((i=$.inArray(jqxhr,xhrQueue)) > -1){
xhrQueue.splice(i,1); //alert("C:"+settings.url);
}
});
ajaxAbort = function (){ //alert("abortStart");
var i=0;
while(xhrQueue.length){
xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
}
};
Mieux vaut utiliser un code indépendant .....
var xhrQueue = [];
$(document).ajaxSend(function(event,jqxhr,settings){
xhrQueue.Push(jqxhr); //alert(settings.url);
});
$(document).ajaxComplete(function(event,jqxhr,settings){
var i;
if((i=$.inArray(jqxhr,xhrQueue)) > -1){
xhrQueue.splice(i,1); //alert("C:"+settings.url);
}
});
ajaxAbort = function (){ //alert("abortStart");
var i=0;
while(xhrQueue.length){
xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
}
};
var Request = {
List: [],
AbortAll: function () {
var _self = this;
$.each(_self.List, (i, v) => {
v.abort();
});
}
}
var settings = {
"url": "http://localhost",
success: function (resp) {
console.log(resp)
}
}
Request.List.Push($.ajax(settings));
chaque fois que vous voulez abandonner toute la requête ajax, il vous suffit d'appeler cette ligne
Request.AbortAll()
Il est tout aussi important de dire que vous voulez vous déconnecter et que vous générez de nouvelles demandes avec des minuteries: parce que les données de session sont renouvelées à chaque nouvelle bootstrap (vous pouvez peut-être dire que je parle Drupal, mais ce peut être n'importe quel site qui utilise des sessions) ... je devais parcourir tous mes scripts avec une recherche et remplacement, parce que j'avais une tonne de choses en cours d'exécution dans différents cas: les variables globales en haut:
var ajReq = [];
var canAj = true;
function abort_all(){
for(x in ajReq){
ajReq[x].abort();
ajReq.splice(x, 1)
}
canAj = false;
}
function rmvReq(ranNum){
var temp = [];
var i = 0;
for(x in ajReq){
if(x == ranNum){
ajReq[x].abort();
ajReq.splice(x, 1);
}
i++;
}
}
function randReqIndx(){
if(!canAj){ return 0; }
return Math.random()*1000;
}
function getReqIndx(){
var ranNum;
if(ajReq.length){
while(!ranNum){
ranNum = randReqIndx();
for(x in ajReq){
if(x===ranNum){
ranNum = null;
}
}
}
return ranMum;
}
return randReqIndx();
}
$(document).ready(function(){
$("a").each(function(){
if($(this).attr('href').indexOf('/logout')!=-1){
$(this).click(function(){
abort_all();
});
}
})
});
// Then in all of my scripts I wrapped my ajax calls... If anyone has a suggestion for a
// global way to do this, please post
var reqIndx = getReqIndx();
if(reqIndx!=0){
ajReq[reqIndx] = $.post(ajax, { 'action': 'update_quantities', iids:iidstr, qtys:qtystr },
function(data){
//..do stuff
rmvReq(reqIndx);
},'json');
}