Arrêtez toutes les demandes ajax actives dans jQuery

216

J'ai un problème lors de la soumission d'un formulaire, toutes les demandes ajax actives échouent et cela déclenche un événement d'erreur.

Comment arrêter toutes les requêtes ajax actives dans jQuery sans déclencher d'événement d'erreur?

umpirsky
la source

Réponses:

273

Chaque fois que vous créez une requête 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 pour garder une trace de toutes les demandes ajax en attente et les annuler si nécessaire.

Darin Dimitrov
la source
THX, j'ai ajouté un FLAG parce que j'ai utilisé plusieurs requêtes en même temps
jcho360
voici un exemple de travail simple: stackoverflow.com/a/42312101/3818394
Dharmesh patel
j'ai un appel ajax en fonction comment puis-je l'interrompre?
Kalariya_M
La variable doit être déclarée globale pour y accéder à partir d'une autre fonction lorsqu'un appel ajax est en cours. exemple: un processus de téléchargement multi-fichiers.
Clain Dsilva
180

L'extrait de code suivant vous permet de conserver une liste ( pool ) de demandes et de les annuler toutes si nécessaire. Il est préférable de le placer dans <HEAD>votre html, avant tout autre appel AJAX.

<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>
mkmurray
la source
2
@mkmurray - sur l'initalisation dans IE8, je semble obtenir Object doesn't support property or method 'indexOf'? Je soupçonne que ce pourrait être stackoverflow.com/a/2608601/181971 ou peut-être simplement basculer vers stackoverflow.com/a/2608618/181971 ?
Tim
3
@grr a raison, consultez sa réponse et consultez les documents pour ajaxSetup .
kzfabi
@Tim - comme Steven l'a suggéré, au lieu de var index = $ .xhrPool.indexOf (jqXHR); use: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Cela montre TypeError: jqXHR.abort n'est pas une fonction pour moi. :(
Shesha
Il y a une légère erreur logique dans la méthode abortAll, qui est corrigée ici dans cette réponse stackoverflow.com/a/45500874/1041341
Sarin JS
122

Utiliser ajaxSetup n'est pas correct , comme indiqué sur sa page doc. Il ne définit que les valeurs par défaut, et si certaines demandes les remplacent, il y aura un gâchis.

Je suis bien en retard à la fête, mais juste pour référence future si quelqu'un cherche une solution au même problème, voici mon coup, inspiré 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);
grr
la source
Comment appelle-t-on la méthode abort () à partir d'autres fonctions?
Stan James
abandonner est une fonction, pas une méthode. vous l'appelez normalement dans la même encapsulation, si vous devez l'utiliser en dehors de l'encapsulation, vous pouvez supprimer le "var" devant le nom de la fonction et il deviendra une fonction disponible dans le monde entier
Trey
Salut, quelqu'un pourrait-il expliquer quand r ne sera pas défini?
Varun
36

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 des underscore.js est présent, mais évidemment pas nécessaire. Je suis juste paresseux et je ne veux pas le changer en $ .each (). 8P

Andy Ferra
la source
2
J'ai une solution légèrement modifiée qui fonctionne très bien que je suis sur le point de publier.
mkmurray
7
Cela fuit la mémoire. aboutAlldevrait supprimer les éléments du tableau. De plus, lorsqu'une demande est terminée, elle doit se retirer de la liste.
Behrang Saeedzadeh
5
@BehrangSaeedzadeh Vous auriez également dû publier une version améliorée.
mattsven
19

Donnez à chaque requête xhr un identifiant unique et stockez la référence d'objet dans un objet avant de l'envoyer. Supprimez la référence une fois la demande xhr terminée.

Pour annuler toute demande à tout moment:

$.ajaxQ.abortAll();

Renvoie les identifiants uniques de la demande annulée. Uniquement à 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;
    }
  };

})();

Renvoie un objet avec une fonction unique qui peut être utilisé pour ajouter plus de fonctionnalités si nécessaire.

refik
la source
17

Je l'ai trouvé trop facile pour plusieurs demandes.

étape1: définir une variable en haut de page:

  xhrPool = []; // no need to use **var**

step2: définir beforeSend dans toutes les requêtes ajax:

  $.ajax({
   ...
   beforeSend: function (jqXHR, settings) {
        xhrPool.push(jqXHR);
    },
    ...

étape 3: utilisez-la partout où vous en avez besoin:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Patel de Dharmesh
la source
Cela fuit la mémoire, tout comme stackoverflow.com/a/6618288/1772379 , et précisément pour les mêmes raisons.
Ben Johnson
Façon vraiment horrible d'écrire JavaScript.
Ozil
1
peut être à la fin, vous pouvez effacer / vider le tableau xhrPool
espace terre
6

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 désormais éventuellement accepter une URL comme paramètre et n'annulera que les appels en attente vers cette URL

kofifus
la source
5

J'ai eu quelques problèmes avec le code d'Andy, mais cela m'a donné de bonnes 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 de faire les choses ajaxComplete (). Peu importe comment j'ai essayé de configurer .ajaxSetup, cela n'a pas fonctionné.

le Hampster
la source
7
Je pense que vous appelez peut-être pop sur la mauvaise demande si elles ne se terminent pas dans un ordre particulier?
jjmontes
1
Oui, vous voulez faire de la tranche au lieu de la pop. J'ai une solution légèrement modifiée que je vais publier.
mkmurray
4

J'ai mis à jour le code pour le faire fonctionner 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);
        }
    }
});
Steven
la source
4

Jeter mon chapeau. Offres abortet removeméthodes contre le xhrPooltableau, et n'est pas sujet à des problèmes avec des ajaxSetupremplacements.

/**
 * 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);
});
onassar
la source
2

Faites un pool de toutes les demandes ajax et annulez-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++]);
    }
};
Zigri2612
la source
1

Mieux vaut utiliser du 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++]);
    }
};
Zigri2612
la source
0

Tout aussi important: dites que vous voulez vous déconnecter et que vous générez de nouvelles requêtes avec des minuteries: parce que les données de session sont renouvelées à chaque nouveau bootstrap (peut-être pouvez-vous dire que je parle de Drupal, mais cela pourrait être n'importe quel site qui utilise des sessions). J'ai dû parcourir tous mes scripts avec une recherche et un remplacement, car j'avais une tonne de choses en cours d'exécution dans différents cas: 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');
}
Bonnes nouvelles
la source
0
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 demande ajax, il vous suffit d'appeler cette ligne

Request.AbortAll()
Omid Matouri
la source
-2

Il existe une solution factice, je l'utilise pour abandonner toutes les demandes ajax. Cette solution consiste à recharger toute la page. Cette solution est bonne si vous n'aimez pas attribuer un ID à chaque demande ajax et si vous faites des demandes ajax à l'intérieur de for-loop. Cela garantira que toutes les demandes ajax sont supprimées.

location.reload();
ASammour
la source
-3

Voici comment connecter cela à n'importe quel clic (utile si votre page passe de nombreux appels AJAX et que vous essayez de vous éloigner).

$ ->
    $.xhrPool = [];

$(document).ajaxSend (e, jqXHR, options) ->
    $.xhrPool.push(jqXHR)

$(document).ajaxComplete (e, jqXHR, options) ->
    $.xhrPool = $.grep($.xhrPool, (x) -> return x != jqXHR);

$(document).delegate 'a', 'click', ->
    while (request = $.xhrPool.pop())
      request.abort()
dB.
la source