2010-12-29 16 views
229

Mam żądanie AJAX, które będzie wykonywane co 5 sekund. Ale problem jest przed żądaniem AJAX, jeśli poprzednie żądanie nie zostało zakończone Muszę przerwać to żądanie i złożyć nowe żądanie.Jak anulować/anulować żądanie jQuery AJAX?

Mój kod jest podobny do tego, jak rozwiązać ten problem?

$(document).ready(
    var fn = function(){ 
     $.ajax({ 
      url: 'ajax/progress.ftl', 
      success: function(data) { 
       //do something 
      } 
     }); 
    }; 

    var interval = setInterval(fn, 500); 
); 
+10

możliwe duplikat [. Zabić ajax żądania użyciu JavaScript jquery] (http://stackoverflow.com/questions/446594/kill-ajax-requests-using-javascript-using-jquery) – karim79

+5

Twoje pytanie mówi, że żądanie powinno się zdarzyć co 5 sekund, ale kod używa 500 ms = 0,5 s. – geon

Odpowiedz

331

Metoda ajax jquery zwraca obiekt XMLHttpRequest. Możesz użyć tego obiektu, aby anulować żądanie.

XMLHttpRequest ma abort metodę, która anuluje żądanie, ale jeśli wniosek został już wysłany do serwera następnie serwer będzie przetwarzać żądania nawet jeśli przerwać żądanie, ale klient nie będzie czekał na/obsłużyć odpowiedź.

Obiekt xhr zawiera również readyState, który zawiera stan żądania (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 i DONE-4). możemy tego użyć, aby sprawdzić, czy poprzednie żądanie zostało ukończone.

$(document).ready(
    var xhr; 

    var fn = function(){ 
     if(xhr && xhr.readyState != 4){ 
      xhr.abort(); 
     } 
     xhr = $.ajax({ 
      url: 'ajax/progress.ftl', 
      success: function(data) { 
       //do something 
      } 
     }); 
    }; 

    var interval = setInterval(fn, 500); 
); 
+3

@rtpHarry Dzięki za aktualizację jQuery 1.5 –

+59

@romkyns Różnice to właściwość 'readystate' powyżej i' readyState' poniżej, znak 's' jest pisany wielkimi literami w jQuery 1.5 –

+1

Rzeczywiście, dziękuję! –

3

Dlaczego powinieneś przerwać żądanie?

Jeśli każde żądanie trwa dłużej niż pięć sekund, co się stanie?

Nie należy przerywać żądania, jeśli parametr przekazujący z żądaniem się nie zmienia. np .: - żądanie dotyczy odzyskania danych powiadomienia. W takich sytuacjach przyjemnym podejściem jest ustawienie nowego żądania dopiero po wypełnieniu poprzedniego żądania Ajax.

$(document).ready(

    var fn = function(){ 

     $.ajax({ 
      url: 'ajax/progress.ftl', 
      success: function(data) { 
       //do something 
      }, 

      complete: function(){setTimeout(fn, 500);} 
     }); 
    }; 

    var interval = setTimeout(fn, 500); 

); 
+3

To jest zły pomysł. Podczas rozpoczynania nowego połączenia nie chcesz, aby pełne zdarzenie zostało uruchomione z poprzedniego połączenia. Dzięki temu podejściu możesz uzyskać bardzo dziwne wyniki. – Webberig

+0

@Webberig Dzięki! zaktualizował odpowiedź w tej sytuacji. –

0

Po zgłoszeniu się do serwera spraw, aby sprawdził, czy postęp nie jest pusty (lub pobiera dane). Jeśli pobiera dane, przerwij poprzednie żądanie i zainicjuj nowe.

var progress = null 

function fn() {  
    if (progress) { 
     progress.abort(); 
    } 
    progress = $.ajax('ajax/progress.ftl', { 
     success: function(data) { 
      //do something 
      progress = null; 
     } 
    }); 
} 
0

jQuery: wykorzystać jako punkt wyjściowy - jak wdechu. Rozwiązałem to tak: (nie jest to idealne rozwiązanie, po prostu przerywa ostatnią instancję i jest kod WIP)

var singleAjax = function singleAjax_constructor(url, params) { 
    // remember last jQuery's get request 
    if (this.lastInstance) { 
     this.lastInstance.abort(); // triggers .always() and .fail() 
     this.lastInstance = false; 
    } 

    // how to use Deferred : http://api.jquery.com/category/deferred-object/ 
    var $def = new $.Deferred(); 

    // pass the deferrer's request handlers into the get response handlers 
    this.lastInstance = $.get(url, params) 
     .fail($def.reject)   // triggers .always() and .fail() 
     .success($def.resolve); // triggers .always() and .done() 

    // return the deferrer's "control object", the promise object 
    return $def.promise(); 
} 


// initiate first call 
singleAjax('/ajax.php', {a: 1, b: 2}) 
    .always(function(a,b,c) {console && console.log(a,b,c);}); 

// second call kills first one 
singleAjax('/ajax.php', {a: 1, b: 2}) 
    .always(function(a,b,c) {console && console.log(a,b,c);}); 
    // here you might use .always() .fail() .success() etc. 
-7

Należy również sprawdzić readyState 0. Ponieważ podczas korzystania xhr.abort () funkcja ta ustawiona readyState 0 w tym obiekcie, a jeśli kontrola będzie zawsze prawdziwe - readyState = 4

$(document).ready(
    var xhr; 

    var fn = function(){ 
     if(xhr && xhr.readyState != 4 && xhr.readyState != 0){ 
      xhr.abort(); 
     } 
     xhr = $.ajax({ 
      url: 'ajax/progress.ftl', 
      success: function(data) { 
       //do something 
      } 
     }); 
    }; 

    var interval = setInterval(fn, 500); 
); 
+2

Czy skopiowałeś i wkleiłeś odpowiedź Aruna? Ponieważ prawdopodobieństwo, że dwa bloki kodu będą dokładnie takie same, odstępy i wszystkie ... –

+0

@ user2700923 Jego wpis nie jest dokładnie taki sam. Chodzi o to, że powinniśmy również sprawdzić ReadyState 0. Byłoby to jednak bardziej odpowiednie jako komentarz do odpowiedzi Aruna. – Stefan

5

wiem, że to może być trochę za późno, ale doświadczają podobnych problemów, gdzie wywołanie metody abort didnt naprawdę przerwał wniosek. zamiast tego przeglądarka wciąż czekała na odpowiedź, której nigdy nie używa. ten kod rozwiązał ten problem.

try { 
     xhr.onreadystatechange = null; 
     xhr.abort(); 
} catch (e) {} 
+0

Miał ten sam problem i to zadziałało. –

0

Można użyć jquery-validate.js. Poniżej znajduje się fragment kodu z jquery-validate.js.

// ajax mode: abort 
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 

var pendingRequests = {}, 
    ajax; 
// Use a prefilter if available (1.5+) 
if ($.ajaxPrefilter) { 
    $.ajaxPrefilter(function(settings, _, xhr) { 
     var port = settings.port; 
     if (settings.mode === "abort") { 
      if (pendingRequests[port]) { 
       pendingRequests[port].abort(); 
      } 
      pendingRequests[port] = xhr; 
     } 
    }); 
} else { 
    // Proxy ajax 
    ajax = $.ajax; 
    $.ajax = function(settings) { 
     var mode = ("mode" in settings ? settings : $.ajaxSettings).mode, 
      port = ("port" in settings ? settings : $.ajaxSettings).port; 
     if (mode === "abort") { 
      if (pendingRequests[port]) { 
       pendingRequests[port].abort(); 
      } 
      pendingRequests[port] = ajax.apply(this, arguments); 
      return pendingRequests[port]; 
     } 
     return ajax.apply(this, arguments); 
    }; 
} 

tak, że po prostu wystarczy ustawić parametr tryb do przerwać podczas dokonywania ajax żądania.

Ref https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js