Przerwij żądania Ajax za pomocą jQuery

1827

Używając jQuery, jak mogę anulować / przerwać żądanie Ajax , z którego jeszcze nie otrzymałem odpowiedzi?

lukewm
źródło
2
Może źle zrozumiałem pytanie, ale nie możesz po prostu użyć $.ajaxStop?
Luke Madhanga,
17
@LukeMadhanga; Myślę, że ajaxStopwykrywa tylko, gdy wszystkie żądania AJAX są kompletne, nie zatrzymuje żądania. Z mojego doświadczenia wynika, że używasz go tak: $(document).ajaxStop(function(){alert("All done")}). Korzystanie .abort()jest najlepszą opcją.
TheCarver

Odpowiedzi:

1744

Większość metod Ajax jQuery zwraca obiekt XMLHttpRequest (lub równoważny), więc możesz po prostu użyć abort().

Zobacz dokumentację:

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

AKTUALIZACJA: Od jQuery 1.5 zwracany obiekt jest opakowaniem dla natywnego obiektu XMLHttpRequest o nazwie jqXHR. Ten obiekt wydaje się ujawniać wszystkie natywne właściwości i metody, więc powyższy przykład nadal działa. Zobacz Obiekt jqXHR (dokumentacja API jQuery).

AKTUALIZACJA 2: Od jQuery 3 metoda ajax zwraca teraz obietnicę z dodatkowymi metodami (jak przerwanie), więc powyższy kod nadal działa, chociaż zwracany obiekt już nie jest xhr. Zobacz blog 3.0 tutaj .

AKTUALIZACJA 3 : xhr.abort()nadal działa na jQuery 3.x. Nie zakładaj, że aktualizacja 2 jest poprawna. Więcej informacji o repozytorium jQuery Github .

miau
źródło
12
To jest jak kliknięcie przycisku „stop” w przeglądarce. Anuluje żądanie. Następnie możesz ponownie użyć tego samego obiektu XHR do kolejnego żądania.
meouw
65
@brad Niestety abortnie zamyka ustanowionego połączenia z serwerem, więc successnadal będzie wywoływane. Jest to bardzo problematyczne w przypadku implementacji komety z długim odpytywaniem.
pepkin88
6
@ErvWalter Możesz wysłać kolejne żądanie, które anuluje poprzednie.
Asad Saeeduddin,
8
W moich testach żądanie jest przerywane w przeglądarce, ale metoda .fail () jest wywoływana z jqXHR, status = 0 i jqXHR, statusMessage = "abort"
BJ Safdie
9
.abort()nadal działa dla mnie w jQuery 3.2.1. Ten komentarz w powiązanym numerze github autorstwa członka zespołu podstawowego jQuery wydaje się sugerować, że ta odpowiedź jest niepoprawna i .abort() nie została usunięta.
alarive
117

Nie można odwołać żądania, ale można ustawić wartość limitu czasu, po której odpowiedź zostanie zignorowana. Zobacz tę stronę, aby zapoznać się z opcjami AJAX jquery. Uważam, że Twoje żądanie oddzwonienia zostanie wywołane, jeśli limit czasu zostanie przekroczony. Istnieje już domyślny limit czasu dla każdego żądania AJAX.

Można również użyć abort () metody na obiekcie żądania, ale jednocześnie spowoduje to klient przestać słuchać do imprezy, to może prawdopodobnie nie będzie zatrzymać serwer z jej przetwarzanie.

tvanfosson
źródło
74

Jest to żądanie asynchroniczne , co oznacza, że ​​po wysłaniu zostaje wysłane.

W przypadku, gdy serwer rozpoczyna bardzo kosztowną operację z powodu żądania AJAX, najlepiej jest otworzyć serwer, aby nasłuchiwać żądań anulowania, i wysłać osobne żądanie AJAX, powiadamiając serwer o zaprzestaniu tego, co robi.

W przeciwnym razie po prostu zignoruj ​​odpowiedź AJAX.

Yuval Adam
źródło
48
W tym kontekście asynchroniczny oznacza po prostu, że żądanie nie zakłóca przepływu skryptu. Przeglądarki mają teraz możliwość przedwczesnego przerwania żądania przed jego zakończeniem.
ElephantHunter,
4
Jak możemy wysłać żądanie anulowania na serwer? Nie rozumiem, skąd serwer będzie wiedział, które żądanie przerwać przetwarzanie? Czy możesz podać przykład? Dziękuję Ci.
Lucky Soni
3
@LuckySoni, Elephanthunter dyskutuje tylko po stronie klienta. Na serwer nie wpłynie żądanie
.abort
4
@Kloar, jeśli żądanie nie zostanie jeszcze odebrane przez serwer (np. Duże żądania wieloczęściowe), klient może zamknąć gniazdo i wpłynie to na serwer.
biały
4
PHP automatycznie sprawdza przerwane żądania, a także automatycznie się kończy. patrz php.net/manual/en/function.ignore-user-abort.php
hanshenrik
68

Zapisz wywołania wykonane w tablicy, a następnie wywołaj xhr.abort () na każdym z nich.

OGROMNY PRZESTROGA: Możesz przerwać żądanie, ale to tylko strona klienta. Strona serwera może nadal przetwarzać żądanie. Jeśli używasz czegoś takiego jak PHP lub ASP z danymi sesji, dane sesji są blokowane do czasu zakończenia aukcji ajax. Tak więc, aby umożliwić użytkownikowi kontynuowanie przeglądania witryny, musisz wywołać session_write_close (). Spowoduje to zapisanie sesji i odblokowanie, dzięki czemu inne strony oczekujące na kontynuację będą kontynuowane. Bez tego kilka stron może czekać na usunięcie blokady.

Tei
źródło
skoro zawsze anulujesz poprzednią, czy nie zawsze możesz to zrobić? (i nie trzeba używać tablicy)
nonpolarity
60

Żądania AJAX mogą nie zostać ukończone w kolejności, w jakiej zostały uruchomione. Zamiast przerywać, możesz zignorować wszystkie odpowiedzi AJAX, z wyjątkiem ostatniej:

  • Utwórz licznik
  • Zwiększ licznik podczas inicjowania żądania AJAX
  • Użyj bieżącej wartości licznika do „stemplowania” żądania
  • W przypadku wywołania zwrotnego porównania porównaj znaczek z licznikiem, aby sprawdzić, czy było to ostatnie żądanie

Szorstki zarys kodu:

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

Salman A.
źródło
Z powodu zastrzeżeń dotyczących anulowania żądania XHR (zobacz inne komentarze na tej stronie), jest to prawdopodobnie najlepsza i najprostsza opcja.
Quinn Comendant
41

Musieliśmy tylko obejść ten problem i przetestować trzy różne podejścia.

  1. anuluje żądanie zgodnie z sugestią @meouw
  2. wykonać wszystkie żądania, ale przetwarza tylko wynik ostatniego przesłania
  3. zapobiega nowym żądaniom, dopóki inne nie jest jeszcze w toku

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

W naszym przypadku postanowiliśmy zastosować podejście nr 3, ponieważ powoduje ono mniejsze obciążenie serwera. Ale nie jestem w 100% pewien, czy jeśli jQuery gwarantuje wywołanie metody .complete (), może to spowodować sytuację zakleszczenia. W naszych testach nie mogliśmy odtworzyć takiej sytuacji.

oyophant
źródło
36

Zawsze najlepszą praktyką jest zrobienie czegoś takiego.

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

O wiele lepiej jest jednak sprawdzić instrukcję if, aby sprawdzić, czy żądanie ajax jest puste, czy nie.

Tharindu Kumara
źródło
2
Sprawdzam również, czy żądanie już działa, ale używam wartości logicznej, ponieważ jest on lżejszy.
Kliknij tutaj,
15

Po prostu zadzwoń do xhr. abort (), czy jest to obiekt ajax jquery, czy natywny obiekt XMLHTTPRequest.

przykład:

//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
źródło
13

Robiłem rozwiązanie do wyszukiwania na żywo i potrzebowałem anulować oczekujące żądania, które mogły potrwać dłużej niż ostatnie / najbardziej aktualne żądanie.

W moim przypadku użyłem czegoś takiego:

//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 
Pałka policjanta
źródło
12

Jak zauważyło wiele osób w wątku, tylko dlatego, że żądanie zostało przerwane po stronie klienta, serwer nadal będzie je przetwarzał. Powoduje to niepotrzebne obciążenie serwera, ponieważ wykonuje pracę, której przestaliśmy słuchać w interfejsie.

Problem, który próbowałem rozwiązać (do którego mogą się również napotkać inni), polega na tym, że kiedy użytkownik wpisał informacje w polu wejściowym, chciałem wystosować prośbę o działanie typu Google Instant.

Aby uniknąć wystrzeliwania niepotrzebnych próśb i zachować szybkość interfejsu, wykonałem następujące czynności:

var xhrQueue = [];
var xhrCount = 0;

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

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

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

    }, 150);

});

Spowoduje to zasadniczo wysłanie jednego żądania co 150 ms (zmienną, którą można dostosować do własnych potrzeb). Jeżeli masz problemy ze zrozumieniem tego, co dokładnie dzieje się tutaj, zalogować xhrCounti xhrQueuedo konsoli tuż przed jeśli bloku.

brianrhea
źródło
11

Wystarczy użyć ajax.abort (), na przykład możesz przerwać wszelkie oczekujące żądania ajax przed wysłaniem kolejnego takiego

//check for existing ajax request
if(ajax){ 
 ajax.abort();
 }
//then you make another ajax request
$.ajax(
 //your code here
  );
Joecoder001
źródło
11

Za pomocą tego możesz przerwać dowolne ciągłe wywołanie ajax

<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
źródło
10

nie ma niezawodnego sposobu, aby to zrobić, a ja nawet nie spróbowałbym tego, gdy żądanie jest w ruchu; tylko sposób racjonalnie reagować jest zignorować odpowiedź.

w większości przypadków może się to zdarzyć w sytuacjach takich jak: użytkownik zbyt często klika przycisk uruchamiający wiele kolejnych XHR, tutaj masz wiele opcji, albo blokuj przycisk, aż XHR zostanie zwrócony, albo nawet nie uruchamiaj nowego XHR, podczas gdy inny uruchamia podpowiedź użytkownik odchyli się do tyłu - lub odrzuci każdą oczekującą odpowiedź XHR oprócz ostatniej.

chodź weź trochę
źródło
7

Poniższy kod pokazuje inicjowanie i przerywanie żądania 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
źródło
5
Proszę wyjaśnić, w jaki sposób rozwiązuje to pytanie. Pomoże to OP i innym przyszłym osobom poszukującym.
SnareChops
5

Miałem problem z odpytywaniem i po zamknięciu strony ankieta była kontynuowana, więc z mojej przyczyny użytkownik przegapiłby aktualizację, ponieważ wartość mysql była ustawiana na następne 50 sekund po zamknięciu strony, mimo że zabiłem żądanie ajax, ja zastanawiałem się, używając $ _SESSION do ustawienia zmiennej var nie aktualizuje się w ankiecie, dopóki się nie skończy i nie rozpocznie się nowa, więc to, co zrobiłem, ustawiło wartość w mojej bazie danych na 0 = offpage, podczas gdy ja odpytywanie Odpytuję ten wiersz i zwracam false; gdy jest 0, ponieważ zapytanie w sondowaniu dostarczy ci oczywiście bieżące wartości ...

Mam nadzieję, że to pomogło

Marcus
źródło
5

Jeśli xhr.abort(); spowoduje to ponowne załadowanie strony,

Następnie możesz ustawić onreadystatechangeprzed przerwaniem, aby zapobiec:

// ↓ prevent page reload by abort()
xhr.onreadystatechange = null;
// ↓ may cause page reload
xhr.abort();
Vikyd
źródło
4

Udostępniłem demo, które pokazuje, jak anulować żądanie AJAX - jeśli dane nie zostaną zwrócone z serwera w określonym czasie oczekiwania.

HTML:

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

KOD 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
źródło
1
$.ajaxzapewnia timeoutopcję, więc nie musisz pisać własnej. Po prostu użyj ..., data: {...}, timeout: waitTime,....
Bram Vanroy,