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?


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 .


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.


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.


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.


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


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.


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.


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

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 

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.


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

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>

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.


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

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


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

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

1
$.ajaxzapewnia timeoutopcję, więc nie musisz pisać własnej. Po prostu użyj ..., data: {...}, timeout: waitTime,....
Bram Vanroy,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.