web-dev-qa-db-fra.com

Arrêtez toutes les requêtes ajax actives dans jQuery

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?

207
umpirsky

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.

264
Darin Dimitrov

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>
180
mkmurray

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);
120
grr

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

36
Andy Ferra

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.

17
refik

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();
    });
14
Dharmesh patel

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.

5
kofifus

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é.

5
the Hampster

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);
        }
    }
});
4
Steven

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);
});
4
onassar

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++]);
    }
};
2
Zigri2612

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++]);
    }
};
1
Zigri2612
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()
0
Omid Maturi

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');
}
0
GoodNews