Annulla le richieste Ajax usando jQuery


1827

Utilizzando jQuery, come posso annullare / interrompere una richiesta Ajax da cui non ho ancora ricevuto la risposta?


2
Forse ho frainteso la domanda, ma non potresti semplicemente usare $.ajaxStop?
Luke Madhanga,

17
@LukeMadhanga; Penso che ajaxStoprilevi solo quando tutte le richieste AJAX sono complete, non ferma una richiesta. Nella mia esperienza, si può usare in questo modo: $(document).ajaxStop(function(){alert("All done")}). L'utilizzo .abort()è l'opzione migliore.
TheCarver

Risposte:


1744

La maggior parte dei metodi Ajax jQuery restituisce un oggetto XMLHttpRequest (o l'equivalente), quindi puoi semplicemente usarlo abort().

Vedi la documentazione:

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()

AGGIORNAMENTO: A partire da jQuery 1.5 l'oggetto restituito è un wrapper per l'oggetto XMLHttpRequest nativo chiamato jqXHR. Questo oggetto sembra esporre tutte le proprietà e i metodi nativi, quindi l'esempio sopra funziona ancora. Vedere L'oggetto jqXHR (documentazione dell'API jQuery).

AGGIORNAMENTO 2: A partire da jQuery 3, il metodo ajax ora restituisce una promessa con metodi extra (come l'interruzione), quindi il codice sopra riportato continua a funzionare, sebbene l'oggetto che viene restituito non xhrsia più. Vedi il blog 3.0 qui .

AGGIORNAMENTO 3 : xhr.abort()funziona ancora su jQuery 3.x. Non dare per scontato che l' aggiornamento 2 sia corretto. Maggiori informazioni sul repository jQuery Github .


12
È come fare clic sul pulsante "stop" sul browser. Annulla la richiesta. È quindi possibile riutilizzare lo stesso oggetto XHR per un'altra richiesta.
Meouw

65
@brad Sfortunatamente, abortnon chiude una connessione stabilita con il server, quindi successverrà comunque chiamato. Questo è molto problematico per le implementazioni di Comet con polling lungo.
pepkin88,

6
@ErvWalter È possibile inviare un'altra richiesta che annulla la precedente.
Asad Saeeduddin,

8
Nei miei test, la richiesta viene interrotta nel browser, ma il metodo .fail () viene richiamato con jqXHR, status = 0 e jqXHR, statusMessage = "abort"
BJ Safdie

9
.abort()funziona ancora per me in jQuery 3.2.1. Questo commento in un problema relativo a github da parte di un membro del team principale di jQuery sembra implicare che questa risposta sia errata e che .abort() non sia stata rimossa.
alarive l'

117

Non è possibile richiamare la richiesta ma è possibile impostare un valore di timeout dopo il quale la risposta verrà ignorata. Vedi questa pagina per le opzioni jQuery AJAX. Ritengo che il tuo callback di errore verrà chiamato se il periodo di timeout viene superato. Esiste già un timeout predefinito su ogni richiesta AJAX.

È inoltre possibile utilizzare l'abort () metodo sull'oggetto richiesta, ma, mentre sarà causare il client per interrompere l'ascolto per l'evento, si può probabilmente non si fermerà il server da elaborarlo.


74

È una richiesta asincrona , il che significa che una volta inviata è disponibile.

Nel caso in cui il tuo server stia iniziando un'operazione molto costosa a causa della richiesta AJAX, la cosa migliore che puoi fare è aprire il tuo server per ascoltare le richieste di annullamento e inviare una richiesta AJAX separata avvisando il server di interrompere qualsiasi cosa stia facendo.

Altrimenti, ignora semplicemente la risposta AJAX.


48
In questo contesto, asincrono significa semplicemente che la richiesta non interrompe il flusso dello script. I browser ora hanno la possibilità di interrompere la richiesta prima del completamento della richiesta.
ElephantHunter,

4
Come possiamo inviare una richiesta di annullamento al server? Non capisco come il server saprà quale richiesta interrompere l'elaborazione? Potresti fare un esempio? Grazie.
Lucky Soni,

3
@LuckySoni, Elephanthunter sta solo discutendo sul lato client. Il server non sarà interessato da una richiesta
.abort

4
@Kloar, se la richiesta non è stata ancora ricevuta dal server (ad esempio richieste multipart di grandi dimensioni), il client potrebbe chiudere il socket e il server sarà interessato.
bianco

4
PHP verifica automaticamente le richieste interrotte e termina anche automaticamente. vedi php.net/manual/en/function.ignore-user-abort.php
hanshenrik

68

Salvare le chiamate effettuate in un array, quindi chiamare xhr.abort () su ciascuna.

ENORME CAVEAT: puoi interrompere una richiesta, ma è solo il lato client. Il lato server potrebbe ancora elaborare la richiesta. Se si utilizza qualcosa come PHP o ASP con i dati di sessione, i dati di sessione vengono bloccati fino al termine di Ajax. Pertanto, per consentire all'utente di continuare a navigare nel sito Web, è necessario chiamare session_write_close (). Questo salva la sessione e la sblocca in modo che le altre pagine in attesa di continuare procedano. Senza questo, diverse pagine possono essere in attesa della rimozione del blocco.


dal momento che annulli sempre la precedente, non puoi sempre farlo? (e non è necessario utilizzare un array)
polarità

60

Le richieste AJAX potrebbero non essere completate nell'ordine in cui sono state avviate. Invece di interrompere, puoi scegliere di ignorare tutte le risposte AJAX tranne quella più recente:

  • Crea un contatore
  • Incrementa il contatore quando si avvia la richiesta AJAX
  • Utilizzare il valore corrente del contatore per "timbrare" la richiesta
  • Nel callback di successo confrontare il timbro con il contatore per verificare se era la richiesta più recente

Profilo approssimativo del codice:

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

Demo su jsFiddle


A causa delle avvertenze sull'annullamento di una richiesta XHR (vedere altri commenti in questa pagina), questa è probabilmente l'opzione migliore e più semplice.
Quinn Comendant

41

Dovevamo solo aggirare questo problema e testare tre diversi approcci.

  1. annulla la richiesta come suggerito da @meouw
  2. esegue tutte le richieste ma elabora solo il risultato dell'ultimo invio
  3. impedisce nuove richieste finché ne è ancora in sospeso un'altra

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" />

Nel nostro caso abbiamo deciso di utilizzare l'approccio n. 3 in quanto produce meno carico per il server. Ma non sono sicuro al 100% se jQuery garantisce la chiamata del metodo .complete (), ciò potrebbe produrre una situazione di deadlock. Nei nostri test non siamo riusciti a riprodurre una situazione del genere.


36

È sempre buona prassi fare qualcosa del genere.

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

Ma è molto meglio se controlli un'istruzione if per verificare se la richiesta ajax è nulla o meno.


2
Controllo anche se una richiesta è già in esecuzione, ma utilizzo un valore booleano, poiché è più leggero.
Zesty,

15

Chiama solo xhr. abort () sia esso oggetto jquery ajax o oggetto XMLHTTPRequest nativo.

esempio:

//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);

13

Stavo facendo una soluzione di ricerca dal vivo e avevo bisogno di annullare le richieste in sospeso che potrebbero aver richiesto più tempo della richiesta più recente / più recente.

Nel mio caso ho usato qualcosa del genere:

//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 

12

Come hanno notato molte persone nel thread, solo perché la richiesta viene interrotta sul lato client, il server elaborerà comunque la richiesta. Questo crea un carico inutile sul server perché sta facendo un lavoro che abbiamo smesso di ascoltare sul front-end.

Il problema che stavo cercando di risolvere (a cui potrebbero incorrere anche altri) è che quando l'utente ha inserito le informazioni in un campo di immissione, volevo dare il via a una richiesta per un tipo di sensazione di Google Instant.

Per evitare di lanciare richieste non necessarie e per mantenere la reattività del front-end, ho fatto quanto segue:

var xhrQueue = [];
var xhrCount = 0;

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

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

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

    }, 150);

});

Questo essenzialmente invierà una richiesta ogni 150 ms (una variabile che è possibile personalizzare per le proprie esigenze). Se hai difficoltà a capire cosa sta succedendo esattamente qui, accedi xhrCounte xhrQueuealla console appena prima del blocco if.


11

Usa solo ajax.abort () per esempio potresti interrompere qualsiasi richiesta ajax in sospeso prima di inviarne un'altra come questa

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

11

È possibile interrompere qualsiasi chiamata ajax continua utilizzando questo

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

10

non esiste un modo affidabile per farlo e non proverei nemmeno, una volta che la richiesta è in movimento; l' unico modo per reagire ragionevolmente è ignorare la risposta.

nella maggior parte dei casi, può accadere in situazioni come: un utente fa clic troppo spesso su un pulsante che attiva molti XHR consecutivi, qui hai molte opzioni, o blocca il pulsante fino a quando non viene restituito XHR o non attiva nemmeno il nuovo XHR mentre un altro sta eseguendo un suggerimento l'utente a sporgersi indietro o scartare qualsiasi risposta XHR in sospeso, tranne la recente.


7

Il codice seguente mostra l'avvio e l'interruzione di una richiesta 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!" >

5
Fornisci una spiegazione di come questo risolve la domanda. Ciò aiuterà l'OP e altri futuri ricercatori.
SnareChops

5

Ho avuto il problema del polling e una volta chiusa la pagina il sondaggio è continuato, quindi nella mia causa un utente avrebbe perso un aggiornamento poiché veniva impostato un valore mysql per i successivi 50 secondi dopo la chiusura della pagina, anche se ho ucciso la richiesta ajax, ho pensato in giro, usando $ _SESSION per impostare una var non si aggiorna nel sondaggio fino al suo termine e ne è iniziato uno nuovo, quindi quello che ho fatto è stato impostare un valore nel mio database come 0 = offpage, mentre sono polling interrogo quella riga e restituisco false; quando è 0 poiché l'interrogazione nel polling ti porterà ovviamente ai valori correnti ...

Spero che questo abbia aiutato


5

Se xhr.abort(); causa il ricaricamento della pagina,

Quindi è possibile impostare onreadystatechangeprima di interrompere per impedire:

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

4

Ho condiviso una demo che dimostra come annullare una richiesta AJAX - se i dati non vengono restituiti dal server entro un tempo di attesa predefinito.

HTML:

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

CODICE 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);   
});

1
$.ajaxfornisce timeoutun'opzione in modo da non dover scrivere la tua. Basta usare ..., data: {...}, timeout: waitTime,....
Bram Vanroy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.