Zatrzymaj wszystkie aktywne żądania ajax w jQuery

216

Mam problem, gdy przesyłam formularz, wszystkie aktywne żądania ajax kończą się niepowodzeniem, co powoduje zdarzenie błędu.

Jak zatrzymać wszystkie aktywne żądania ajax w jQuery bez zdarzenia błędu wyzwalania?

umpirsky
źródło

Odpowiedzi:

273

Za każdym razem, gdy tworzysz żądanie ajax, możesz użyć zmiennej do jej przechowywania:

var request = $.ajax({
    type: 'POST',
    url: 'someurl',
    success: function(result){}
});

Następnie możesz przerwać żądanie:

request.abort();

Możesz użyć tablicy śledzącej wszystkie oczekujące żądania ajax i przerwać je w razie potrzeby.

Darin Dimitrov
źródło
Dzięki, dodałem FLAGĘ, ponieważ użyłem wielu żądań w tym samym czasie
jcho360,
tutaj jest prosty przykład działania: stackoverflow.com/a/42312101/3818394
Dharmesh patel
mam wywołanie ajax w funkcji jak mogę to przerwać?
Kalariya_M
Zmienna musi zostać zadeklarowana jako globalna, aby uzyskać do niej dostęp z innej funkcji, gdy trwa wywołanie ajax. przykład: proces przesyłania wielu plików.
Clain Dsilva
180

Poniższy fragment kodu pozwala zachować listę ( pulę ) żądań i przerwać je wszystkie w razie potrzeby. Najlepiej umieścić w <HEAD>pliku HTML, zanim zostaną wykonane inne wywołania AJAX.

<script type="text/javascript">
    $(function() {
        $.xhrPool = [];
        $.xhrPool.abortAll = function() {
            $(this).each(function(i, jqXHR) {   //  cycle through list of recorded connection
                jqXHR.abort();  //  aborts connection
                $.xhrPool.splice(i, 1); //  removes from list by index
            });
        }
        $.ajaxSetup({
            beforeSend: function(jqXHR) { $.xhrPool.push(jqXHR); }, //  annd connection to list
            complete: function(jqXHR) {
                var i = $.xhrPool.indexOf(jqXHR);   //  get index for current connection completed
                if (i > -1) $.xhrPool.splice(i, 1); //  removes from list by index
            }
        });
    })
</script>
mkmurray
źródło
2
@mkmurray - po inicjalizacji w IE8 wydaje się, że dostaję Object doesn't support property or method 'indexOf'? Podejrzewam, że może to być stackoverflow.com/a/2608601/181971, a może po prostu zmienić na stackoverflow.com/a/2608618/181971 ?
Tim
3
@grr ma rację, zapoznaj się z jego odpowiedzią i sprawdź dokumentację dotyczącą ajaxSetup .
kzfabi,
@Tim - jak sugerował Steven, zamiast var index = $ .xhrPool.indexOf (jqXHR); użyj: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Pokazuje TypeError: jqXHR.abort nie jest dla mnie funkcją. :(
Shesha
W metodzie abortAll występuje niewielki błąd logiczny, który został naprawiony tutaj w odpowiedzi stackoverflow.com/a/45500874/1041341
Sarin JS
122

Korzystanie z ajaxSetup jest nieprawidłowe , jak zaznaczono na stronie dokumentu. Ustawia tylko wartości domyślne, a jeśli niektóre żądania zastąpią je, nastąpi bałagan.

Jestem spóźniony na imprezę, ale tylko w celu odniesienia w przyszłości, jeśli ktoś szuka rozwiązania tego samego problemu, oto moje podejście, inspirowane i w dużej mierze identyczne z poprzednimi odpowiedziami, ale bardziej kompletne

// Automatically cancel unfinished ajax requests 
// when the user navigates elsewhere.
(function($) {
  var xhrPool = [];
  $(document).ajaxSend(function(e, jqXHR, options){
    xhrPool.push(jqXHR);
  });
  $(document).ajaxComplete(function(e, jqXHR, options) {
    xhrPool = $.grep(xhrPool, function(x){return x!=jqXHR});
  });
  var abort = function() {
    $.each(xhrPool, function(idx, jqXHR) {
      jqXHR.abort();
    });
  };

  var oldbeforeunload = window.onbeforeunload;
  window.onbeforeunload = function() {
    var r = oldbeforeunload ? oldbeforeunload() : undefined;
    if (r == undefined) {
      // only cancel requests if there is no prompt to stay on the page
      // if there is a prompt, it will likely give the requests enough time to finish
      abort();
    }
    return r;
  }
})(jQuery);
grr
źródło
Jak wywołać metodę abort () z innych funkcji?
Stan James
przerwanie jest funkcją, a nie metodą. wywołujesz go normalnie z tej samej enkapsulacji, jeśli chcesz użyć go poza enkapsulacją, możesz usunąć „var” przed nazwą funkcji i stanie się on globalnie dostępną funkcją
Trey
Cześć, czy ktoś mógłby wyjaśnić, kiedy r będzie niezdefiniowany?
Varun
36

Oto, czego aktualnie używam, aby to osiągnąć.

$.xhrPool = [];
$.xhrPool.abortAll = function() {
  _.each(this, function(jqXHR) {
    jqXHR.abort();
  });
};
$.ajaxSetup({
  beforeSend: function(jqXHR) {
    $.xhrPool.push(jqXHR);
  }
});

Uwaga: _.each underscore.js jest obecny, ale oczywiście nie jest konieczny. Jestem po prostu leniwy i nie chcę go zmieniać na $ .each (). 8 P.

Andy Ferra
źródło
2
Mam nieco zmodyfikowane rozwiązanie, które działa świetnie, które właśnie zamierzam opublikować.
mkmurray
7
To przecieka pamięć. aboutAllpowinien usunąć elementy z tablicy. Ponadto po zakończeniu żądania powinno ono zostać usunięte z listy.
Behrang Saeedzadeh
5
@BehrangSaeedzadeh Powinieneś także opublikować ulepszoną wersję.
mattsven
19

Nadaj każdemu żądaniu xhr unikalny identyfikator i zapisz odwołanie do obiektu w obiekcie przed wysłaniem. Usuń odwołanie po zakończeniu żądania xhr.

Aby anulować wszystkie żądania w dowolnym momencie:

$.ajaxQ.abortAll();

Zwraca unikalne identyfikatory anulowanego żądania. Tylko do celów testowych.

Funkcja pracy:

$.ajaxQ = (function(){
  var id = 0, Q = {};

  $(document).ajaxSend(function(e, jqx){
    jqx._id = ++id;
    Q[jqx._id] = jqx;
  });
  $(document).ajaxComplete(function(e, jqx){
    delete Q[jqx._id];
  });

  return {
    abortAll: function(){
      var r = [];
      $.each(Q, function(i, jqx){
        r.push(jqx._id);
        jqx.abort();
      });
      return r;
    }
  };

})();

Zwraca obiekt z pojedynczą funkcją, którego można użyć, aby w razie potrzeby dodać więcej funkcji.

refik
źródło
17

Uznałem, że jest to zbyt łatwe do wielu żądań.

krok 1: zdefiniuj zmienną na górze strony:

  xhrPool = []; // no need to use **var**

krok 2 : ustaw wcześniej Wyślij we wszystkich żądaniach ajax:

  $.ajax({
   ...
   beforeSend: function (jqXHR, settings) {
        xhrPool.push(jqXHR);
    },
    ...

krok 3: użyj go, gdziekolwiek potrzebujesz:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Patel Dharmesh
źródło
To przecieka pamięć, podobnie jak stackoverflow.com/a/6618288/1772379 i właśnie z tych samych powodów.
Ben Johnson,
Naprawdę okropny sposób na pisanie JavaScript.
Ozil
1
może być na końcu, możesz wyczyścić / opróżnić tablicę xhrPool
kosmiczna ziemia
6

Rozszerzyłem odpowiedź mkmurray i SpYk3HH powyżej, aby xhrPool.abortAll mógł przerwać wszystkie oczekujące żądania danego adresu URL :

$.xhrPool = [];
$.xhrPool.abortAll = function(url) {
    $(this).each(function(i, jqXHR) { //  cycle through list of recorded connection
        console.log('xhrPool.abortAll ' + jqXHR.requestURL);
        if (!url || url === jqXHR.requestURL) {
            jqXHR.abort(); //  aborts connection
            $.xhrPool.splice(i, 1); //  removes from list by index
        }
    });
};
$.ajaxSetup({
    beforeSend: function(jqXHR) {
        $.xhrPool.push(jqXHR); //  add connection to list
    },
    complete: function(jqXHR) {
        var i = $.xhrPool.indexOf(jqXHR); //  get index for current connection completed
        if (i > -1) $.xhrPool.splice(i, 1); //  removes from list by index
    }
});
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    console.log('ajaxPrefilter ' + options.url);
    jqXHR.requestURL = options.url;
});

Użycie jest takie samo, z tym wyjątkiem, że abortAll może teraz opcjonalnie zaakceptować adres URL jako parametr i anuluje tylko oczekujące połączenia z tym adresem URL

Kofifus
źródło
5

Miałem pewne problemy z kodem Andy'ego, ale dało mi to świetne pomysły. Pierwszym problemem było to, że powinniśmy usunąć wszystkie obiekty jqXHR, które zostały pomyślnie ukończone. Musiałem także zmodyfikować funkcję abortAll. Oto mój końcowy działający kod:

$.xhrPool = [];
$.xhrPool.abortAll = function() {
            $(this).each(function(idx, jqXHR) {
                        jqXHR.abort();
                        });
};
$.ajaxSetup({
    beforeSend: function(jqXHR) {
            $.xhrPool.push(jqXHR);
            }
});
$(document).ajaxComplete(function() {
            $.xhrPool.pop();
            });

Nie podobało mi się robienie rzeczy ajaxComplete (). Bez względu na to, jak próbowałem skonfigurować .ajaxSetup, to nie działało.

Hampster
źródło
7
Myślę, że dzwonisz do pop na niewłaściwą prośbę, jeśli nie zostaną wykonane w określonej kolejności?
jjmontes
1
Tak, chcesz zrobić kawałek zamiast popu. Mam nieco zmodyfikowane rozwiązanie, które zamierzam opublikować.
mkmurray
4

Zaktualizowałem kod, aby działał dla mnie

$.xhrPool = [];
$.xhrPool.abortAll = function() {
    $(this).each(function(idx, jqXHR) {
        jqXHR.abort();
    });
    $(this).each(function(idx, jqXHR) {
        var index = $.inArray(jqXHR, $.xhrPool);
        if (index > -1) {
            $.xhrPool.splice(index, 1);
        }
    });
};

$.ajaxSetup({
    beforeSend: function(jqXHR) {
        $.xhrPool.push(jqXHR);
    },
    complete: function(jqXHR) {
        var index = $.inArray(jqXHR, $.xhrPool);
        if (index > -1) {
            $.xhrPool.splice(index, 1);
        }
    }
});
Steven
źródło
4

Wrzucam kapelusz. Oferty aborti removemetody przeciwko xhrPooltablicy, i nie jest podatny na problemy z ajaxSetupprzesłonięciami.

/**
 * Ajax Request Pool
 * 
 * @author Oliver Nassar <[email protected]>
 * @see    http://stackoverflow.com/questions/1802936/stop-all-active-ajax-requests-in-jquery
 */
jQuery.xhrPool = [];

/**
 * jQuery.xhrPool.abortAll
 * 
 * Retrieves all the outbound requests from the array (since the array is going
 * to be modified as requests are aborted), and then loops over each of them to
 * perform the abortion. Doing so will trigger the ajaxComplete event against
 * the document, which will remove the request from the pool-array.
 * 
 * @access public
 * @return void
 */
jQuery.xhrPool.abortAll = function() {
    var requests = [];
    for (var index in this) {
        if (isFinite(index) === true) {
            requests.push(this[index]);
        }
    }
    for (index in requests) {
        requests[index].abort();
    }
};

/**
 * jQuery.xhrPool.remove
 * 
 * Loops over the requests, removes it once (and if) found, and then breaks out
 * of the loop (since nothing else to do).
 * 
 * @access public
 * @param  Object jqXHR
 * @return void
 */
jQuery.xhrPool.remove = function(jqXHR) {
    for (var index in this) {
        if (this[index] === jqXHR) {
            jQuery.xhrPool.splice(index, 1);
            break;
        }
    }
};

/**
 * Below events are attached to the document rather than defined the ajaxSetup
 * to prevent possibly being overridden elsewhere (presumably by accident).
 */
$(document).ajaxSend(function(event, jqXHR, options) {
    jQuery.xhrPool.push(jqXHR);
});
$(document).ajaxComplete(function(event, jqXHR, options) {
    jQuery.xhrPool.remove(jqXHR);
});
onassar
źródło
2

Utwórz pulę wszystkich żądań ajax i przerwij je .....

var xhrQueue = []; 

$(document).ajaxSend(function(event,jqxhr,settings){
    xhrQueue.push(jqxhr); //alert(settings.url);
});

$(document).ajaxComplete(function(event,jqxhr,settings){
    var i;   
    if((i=$.inArray(jqxhr,xhrQueue)) > -1){
        xhrQueue.splice(i,1); //alert("C:"+settings.url);
    }
});

ajaxAbort = function (){  //alert("abortStart");
    var i=0;
    while(xhrQueue.length){ 
        xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
    }
};
Zigri2612
źródło
1

Lepiej używać niezależnego kodu .....

var xhrQueue = []; 

$(document).ajaxSend(function(event,jqxhr,settings){
    xhrQueue.push(jqxhr); //alert(settings.url);
});

$(document).ajaxComplete(function(event,jqxhr,settings){
    var i;   
    if((i=$.inArray(jqxhr,xhrQueue)) > -1){
        xhrQueue.splice(i,1); //alert("C:"+settings.url);
    }
});

ajaxAbort = function (){  //alert("abortStart");
    var i=0;
    while(xhrQueue.length){ 
        xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
    }
};
Zigri2612
źródło
0

Równie ważne: powiedz, że chcesz się wylogować i generujesz nowe żądania za pomocą timerów: ponieważ dane sesji są odnawiane przy każdym nowym bootstrapie (może możesz powiedzieć, że mówię Drupal, ale może to być każda strona, która używa sesji). Musiałem przejść przez wszystkie moje skrypty z wyszukiwaniem i zamianą, ponieważ miałem mnóstwo rzeczy uruchomionych w różnych przypadkach: zmienne globalne u góry:

var ajReq = [];
var canAj = true;
function abort_all(){
 for(x in ajReq){
    ajReq[x].abort();
    ajReq.splice(x, 1)
 }
 canAj = false;
}
function rmvReq(ranNum){
 var temp = [];
 var i = 0;
 for(x in ajReq){
    if(x == ranNum){
     ajReq[x].abort();
     ajReq.splice(x, 1);
    }
    i++;
 }
}
function randReqIndx(){
 if(!canAj){ return 0; }
 return Math.random()*1000;
}
function getReqIndx(){
 var ranNum;
 if(ajReq.length){
    while(!ranNum){
     ranNum = randReqIndx();
     for(x in ajReq){
    if(x===ranNum){
     ranNum = null;
    }
     }
    }
    return ranMum;
 }
 return randReqIndx();
}
$(document).ready(function(){
 $("a").each(function(){
    if($(this).attr('href').indexOf('/logout')!=-1){          
     $(this).click(function(){
    abort_all();                 
     });
    }
 })
});
// Then in all of my scripts I wrapped my ajax calls... If anyone has a suggestion for a 
    // global way to do this, please post
var reqIndx = getReqIndx();
if(reqIndx!=0){
ajReq[reqIndx] = $.post(ajax, { 'action': 'update_quantities', iids:iidstr, qtys:qtystr },  
function(data){
 //..do stuff
 rmvReq(reqIndx);
 },'json');
}
Dobre wieści
źródło
0
var Request = {
    List: [],
    AbortAll: function () {
        var _self = this;
        $.each(_self.List, (i, v) => {
            v.abort();
        });
    }
}
var settings = {
    "url": "http://localhost",
    success: function (resp) {
        console.log(resp)
    }
}

Request.List.push($.ajax(settings));

za każdym razem, gdy chcesz przerwać wszystkie żądania ajax, wystarczy wywołać tę linię

Request.AbortAll()
Omid Matouri
źródło
-2

Istnieje fałszywe rozwiązanie, którego używam do przerywania wszystkich żądań ajax. To rozwiązanie powoduje przeładowanie całej strony. To rozwiązanie jest dobre, jeśli nie chcesz przypisywać identyfikatora do każdego żądania ajax i jeśli tworzysz żądania ajax w pętli for. Dzięki temu wszystkie żądania ajax zostaną zabite.

location.reload();
ASammour
źródło
-3

Oto jak podłączyć to za pomocą dowolnego kliknięcia (przydatne, jeśli twoja strona zawiera wiele wywołań AJAX i próbujesz nawigować dalej).

$ ->
    $.xhrPool = [];

$(document).ajaxSend (e, jqXHR, options) ->
    $.xhrPool.push(jqXHR)

$(document).ajaxComplete (e, jqXHR, options) ->
    $.xhrPool = $.grep($.xhrPool, (x) -> return x != jqXHR);

$(document).delegate 'a', 'click', ->
    while (request = $.xhrPool.pop())
      request.abort()
dB.
źródło