Abandonner les requêtes Ajax à l'aide de jQuery

1827

À l'aide de jQuery, comment puis-je annuler / abandonner une demande Ajax dont je n'ai pas encore reçu la réponse?

tiède
la source
2
J'ai peut-être mal compris la question, mais ne pourriez-vous pas simplement l'utiliser $.ajaxStop?
Luke Madhanga
17
@LukeMadhanga; Je pense ajaxStopque ne détecte que lorsque toutes les demandes AJAX sont terminées, il n'arrête pas une demande. Dans mon expérience, vous l' utiliser comme ceci: $(document).ajaxStop(function(){alert("All done")}). L'utilisation .abort()est la meilleure option.
TheCarver

Réponses:

1744

La plupart des méthodes jQuery Ajax renvoient un objet XMLHttpRequest (ou l'équivalent), vous pouvez donc simplement l'utiliser abort().

Consultez la documentation:

var xhr = $.ajax({
    type: "POST",
    url: "some.php",
    data: "name=John&location=Boston",
    success: function(msg){
       alert( "Data Saved: " + msg );
    }
});

//kill the request
xhr.abort()

MISE À JOUR: Depuis jQuery 1.5, l'objet renvoyé est un wrapper pour l'objet XMLHttpRequest natif appelé jqXHR. Cet objet semble exposer toutes les propriétés et méthodes natives afin que l'exemple ci-dessus fonctionne toujours. Voir L'objet jqXHR (documentation de l'API jQuery).

MISE À JOUR 2: À partir de jQuery 3, la méthode ajax retourne maintenant une promesse avec des méthodes supplémentaires (comme abandonner), donc le code ci-dessus fonctionne toujours, bien que l'objet renvoyé ne xhrsoit plus. Voir le blog 3.0 ici .

MISE À JOUR 3 : xhr.abort()fonctionne toujours sur jQuery 3.x. Ne présumez pas que la mise à jour 2 est correcte. Plus d'informations sur le référentiel jQuery Github .

meouw
la source
12
C'est comme cliquer sur le bouton «stop» de votre navigateur. Il annule la demande. Vous pouvez ensuite réutiliser le même objet XHR pour une autre demande.
meouw
65
@brad Malheureusement, abortne ferme pas une connexion établie avec le serveur, il successsera donc toujours appelé. Ceci est très problématique pour les implémentations de Comet avec une longue interrogation.
pepkin88
6
@ErvWalter Vous pouvez envoyer une autre demande qui annule la précédente.
Asad Saeeduddin
8
Dans mes tests, la demande est abandonnée sur le navigateur, mais la méthode .fail () est invoquée avec un jqXHR, status = 0, et jqXHR, statusMessage = "abort"
BJ Safdie
9
.abort()fonctionne toujours pour moi dans jQuery 3.2.1. Ce commentaire dans un problème lié à github par un membre de l'équipe principale de jQuery semble impliquer que cette réponse est incorrecte et qu'elle .abort() n'a pas été supprimée.
alarive
117

Vous ne pouvez pas rappeler la demande mais vous pouvez définir une valeur de temporisation après laquelle la réponse sera ignorée. Voir cette page pour les options jquery AJAX. Je crois que votre rappel d'erreur sera appelé si le délai d'expiration est dépassé. Il existe déjà un délai d'expiration par défaut pour chaque demande AJAX.

Vous pouvez également utiliser la abort () méthode sur l'objet de la demande , mais, alors qu'il fera le client d'arrêter d' écouter l'événement, il peut probablement pas arrêter le serveur de la traiter.

tvanfosson
la source
74

Il s'agit d'une demande asynchrone , ce qui signifie qu'une fois envoyée, elle est disponible.

Dans le cas où votre serveur démarre une opération très coûteuse en raison de la demande AJAX, le mieux que vous puissiez faire est d'ouvrir votre serveur pour écouter les demandes d'annulation et d'envoyer une demande AJAX distincte notifiant au serveur d'arrêter quoi qu'il fasse.

Sinon, ignorez simplement la réponse AJAX.

Yuval Adam
la source
48
Dans ce contexte, asynchrone signifie simplement que la demande n'interrompt pas le flux du script. Les navigateurs ont désormais la possibilité d'interrompre la demande prématurément avant la fin de la demande.
ElephantHunter
4
Comment envoyer une demande d'annulation au serveur? Je ne comprends pas comment le serveur saura quelle requête pour arrêter le traitement? Pouvez-vous donner un exemple? Je vous remercie.
Lucky Soni
3
@LuckySoni, Elephanthunter ne parle que du côté client. Le serveur ne sera pas affecté par une demande
.abort
4
@Kloar, si la demande n'est pas encore reçue par le serveur (par exemple, les grandes demandes en plusieurs parties), le client peut fermer le socket et le serveur sera affecté.
blanc
4
PHP vérifie automatiquement les demandes abandonnées et se termine automatiquement également. voir php.net/manual/en/function.ignore-user-abort.php
hanshenrik
68

Enregistrez les appels que vous effectuez dans un tableau, puis appelez xhr.abort () sur chacun.

ÉNORME CAVEAT: Vous pouvez abandonner une demande, mais ce n'est que du côté client. Le côté serveur pourrait toujours traiter la demande. Si vous utilisez quelque chose comme PHP ou ASP avec des données de session, les données de session sont verrouillées jusqu'à la fin de l'ajax. Donc, pour permettre à l'utilisateur de continuer à naviguer sur le site Web, vous devez appeler session_write_close (). Cela enregistre la session et la déverrouille afin que les autres pages en attente de continuer se poursuivent. Sans cela, plusieurs pages peuvent attendre que le verrou soit retiré.

Tei
la source
puisque vous annulez toujours la précédente, ne pouvez-vous pas toujours le faire? (et pas besoin d'utiliser un tableau)
non
60

Les demandes AJAX peuvent ne pas se terminer dans l'ordre dans lequel elles ont été lancées. Au lieu d'abandonner, vous pouvez choisir d' ignorer toutes les réponses AJAX à l'exception de la plus récente:

  • Créer un compteur
  • Incrémentez le compteur lorsque vous lancez une demande AJAX
  • Utilisez la valeur actuelle du compteur pour "tamponner" la demande
  • Dans le rappel réussi, comparez le tampon avec le compteur pour vérifier s'il s'agissait de la demande la plus récente

Aperçu approximatif du code:

var xhrCount = 0;
function sendXHR() {
    // sequence number for the current invocation of function
    var seqNumber = ++xhrCount;
    $.post("/echo/json/", { delay: Math.floor(Math.random() * 5) }, function() {
        // this works because of the way closures work
        if (seqNumber === xhrCount) {
            console.log("Process the response");
        } else {
            console.log("Ignore the response");
        }
    });
}
sendXHR();
sendXHR();
sendXHR();
// AJAX requests complete in any order but only the last 
// one will trigger "Process the response" message

Démo sur jsFiddle

Salman A
la source
En raison des mises en garde de l'annulation d'une demande XHR (voir les autres commentaires sur cette page), c'est probablement l'option la meilleure et la plus simple.
Quinn Comendant le
41

Nous avons juste dû contourner ce problème et testé trois approches différentes.

  1. n'annule pas la demande comme suggéré par @meouw
  2. exécuter toutes les demandes mais ne traite que le résultat de la dernière soumission
  3. empêche les nouvelles demandes tant qu'une autre est toujours en attente

var Ajax1 = {
  call: function() {
    if (typeof this.xhr !== 'undefined')
      this.xhr.abort();
    this.xhr = $.ajax({
      url: 'your/long/running/request/path',
      type: 'GET',
      success: function(data) {
        //process response
      }
    });
  }
};
var Ajax2 = {
  counter: 0,
  call: function() {
    var self = this,
      seq = ++this.counter;
    $.ajax({
      url: 'your/long/running/request/path',
      type: 'GET',
      success: function(data) {
        if (seq === self.counter) {
          //process response
        }
      }
    });
  }
};
var Ajax3 = {
  active: false,
  call: function() {
    if (this.active === false) {
      this.active = true;
      var self = this;
      $.ajax({
        url: 'your/long/running/request/path',
        type: 'GET',
        success: function(data) {
          //process response
        },
        complete: function() {
          self.active = false;
        }
      });
    }
  }
};
$(function() {
  $('#button').click(function(e) {
    Ajax3.call();
  });
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="button" type="button" value="click" />

Dans notre cas, nous avons décidé d'utiliser l'approche # 3 car elle produit moins de charge pour le serveur. Mais je ne suis pas sûr à 100% si jQuery garantit l'appel de la méthode .complete (), cela pourrait produire une situation de blocage. Dans nos tests, nous n'avons pas pu reproduire une telle situation.

huître
la source
36

Il est toujours préférable de faire quelque chose comme ça.

var $request;
if ($request != null){ 
    $request.abort();
    $request = null;
}

$request = $.ajax({
    type : "POST", //TODO: Must be changed to POST
    url : "yourfile.php",
    data : "data"
    }).done(function(msg) {
        alert(msg);
    });

Mais il est préférable de vérifier une instruction if pour vérifier si la demande ajax est nulle ou non.

Tharindu Kumara
la source
2
Je vérifie également si une demande est déjà en cours d'exécution, mais j'utilise un booléen, car il est plus léger.
Zesty
15

Appelez simplement xhr. abort () que ce soit un objet jquery ajax ou un objet XMLHTTPRequest natif.

exemple:

//jQuery ajax
$(document).ready(function(){
    var xhr = $.get('/server');
    setTimeout(function(){xhr.abort();}, 2000);
});

//native XMLHTTPRequest
var xhr = new XMLHttpRequest();
xhr.open('GET','/server',true);
xhr.send();
setTimeout(function(){xhr.abort();}, 2000);
cuixiping
la source
13

Je faisais une solution de recherche en direct et je devais annuler les demandes en attente qui peuvent avoir pris plus de temps que la demande la plus récente / la plus récente.

Dans mon cas, j'ai utilisé quelque chose comme ça:

//On document ready
var ajax_inprocess = false;

$(document).ajaxStart(function() {
ajax_inprocess = true;
});

$(document).ajaxStop(function() {
ajax_inprocess = false;
});

//Snippet from live search function
if (ajax_inprocess == true)
{
    request.abort();
}
//Call for new request 
Gamelle
la source
12

Comme l'ont noté de nombreuses personnes sur le fil, juste parce que la demande est abandonnée côté client, le serveur traitera toujours la demande. Cela crée une charge inutile sur le serveur car il fait un travail que nous avons arrêté d'écouter sur le front-end.

Le problème que j'essayais de résoudre (que d'autres pourraient également rencontrer) est que lorsque l'utilisateur a entré des informations dans un champ de saisie, je voulais lancer une demande de type de sensation Google Instant.

Pour éviter de lancer des requêtes inutiles et pour maintenir la vivacité du front-end, j'ai fait ce qui suit:

var xhrQueue = [];
var xhrCount = 0;

$('#search_q').keyup(function(){

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

        if (xhrCount === xhrQueue.length) {
            // Fire Your XHR //
        }

    }, 150);

});

Cela enverra essentiellement une demande toutes les 150 ms (une variable que vous pouvez personnaliser pour vos propres besoins). Si vous ne parvenez pas à comprendre ce qui se passe exactement ici, connectez xhrCount-vous xhrQueueà la console juste avant le bloc if.

brianrhea
la source
11

Utilisez simplement ajax.abort () par exemple, vous pouvez abandonner toute demande ajax en attente avant d'en envoyer une autre comme celle-ci.

//check for existing ajax request
if(ajax){ 
 ajax.abort();
 }
//then you make another ajax request
$.ajax(
 //your code here
  );
Joecoder001
la source
11

Vous pouvez abandonner tout appel ajax continu en utilisant ce

<input id="searchbox" name="searchbox" type="text" />

<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>

<script type="text/javascript">
     var request = null;
        $('#searchbox').keyup(function () {
            var id = $(this).val();
            request = $.ajax({
                type: "POST", //TODO: Must be changed to POST
                url: "index.php",
                data: {'id':id},
                success: function () {

                },
                beforeSend: function () {
                    if (request !== null) {
                        request.abort();
                    }
                }
            });
        });

</script>
Soubhagya Kumar Barik
la source
10

il n'y a pas de moyen fiable de le faire, et je ne voudrais même pas l'essayer, une fois la demande en cours; la seule façon de réagir raisonnablement est d' ignorer la réponse.

dans la plupart des cas, cela peut se produire dans des situations comme: un utilisateur clique trop souvent sur un bouton déclenchant de nombreux XHR consécutifs, ici vous avez de nombreuses options, soit bloquez le bouton jusqu'à ce que XHR soit renvoyé, soit ne déclenchez même pas de nouveau XHR pendant qu'un autre est en cours d'exécution. l'utilisateur de se pencher en arrière - ou de rejeter toute réponse XHR en attente, mais la récente.

viens en chercher
la source
7

Le code suivant montre le lancement et l'annulation d'une demande Ajax:

function libAjax(){
  var req;
  function start(){

  req =    $.ajax({
              url: '1.php',
              success: function(data){
                console.log(data)
              }
            });

  }

  function stop(){
    req.abort();
  }

  return {start:start,stop:stop}
}

var obj = libAjax();

 $(".go").click(function(){


  obj.start();


 })



 $(".stop").click(function(){

  obj.stop();


 })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" class="go" value="GO!" >
   <input type="button" class="stop" value="STOP!" >
zloctb
la source
5
Veuillez expliquer comment cela résout la question. Cela aidera le PO et d'autres futurs chercheurs.
SnareChops
5

J'ai eu le problème de l'interrogation et une fois la page fermée, le sondage s'est poursuivi, donc pour ma cause, un utilisateur manquerait une mise à jour car une valeur mysql était définie pour les 50 secondes suivantes après la fermeture de la page, même si j'ai tué la demande ajax, je figuré, l'utilisation de $ _SESSION pour définir une var ne se mettra pas à jour dans le sondage jusqu'à sa fin et une nouvelle a commencé, donc ce que j'ai fait a été de définir une valeur dans ma base de données comme 0 = offpage, alors que je suis interrogation Je recherche cette ligne et renvoie false; quand il est égal à 0, l'interrogation dans le sondage vous donnera évidemment les valeurs actuelles ...

J'espère que cela a aidé

Marcus
la source
5

Si xhr.abort(); provoque le rechargement de la page,

Vous pouvez ensuite définir onreadystatechangeavant d'abandonner pour éviter:

// ↓ prevent page reload by abort()
xhr.onreadystatechange = null;
// ↓ may cause page reload
xhr.abort();
vikyd
la source
4

J'ai partagé une démo qui montre comment annuler une demande AJAX - si les données ne sont pas retournées par le serveur dans un délai d'attente prédéfini.

HTML:

<div id="info"></div>

CODE JS:

var isDataReceived= false, waitTime= 1000; 
$(function() {
    // Ajax request sent.
     var xhr= $.ajax({
      url: 'http://api.joind.in/v2.1/talks/10889',
      data: {
         format: 'json'
      },     
      dataType: 'jsonp',
      success: function(data) {      
        isDataReceived= true;
        $('#info').text(data.talks[0].talk_title);        
      },
      type: 'GET'
   });
   // Cancel ajax request if data is not loaded within 1sec.
   setTimeout(function(){
     if(!isDataReceived)
     xhr.abort();     
   },waitTime);   
});
ganesh
la source
1
$.ajaxfournit une timeoutoption pour que vous n'ayez pas besoin d'écrire la vôtre. Utilisez simplement ..., data: {...}, timeout: waitTime,....
Bram Vanroy