Stoppen Sie alle aktiven Ajax-Anforderungen in jQuery

216

Ich habe ein Problem, wenn beim Senden eines Formulars alle aktiven Ajax-Anforderungen fehlschlagen und dies ein Fehlerereignis auslöst.

Wie kann ich alle aktiven Ajax-Anforderungen in jQuery stoppen, ohne ein Fehlerereignis auszulösen?

Umpirsky
quelle

Antworten:

273

Jedes Mal, wenn Sie eine Ajax-Anfrage erstellen, können Sie eine Variable zum Speichern verwenden:

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

Dann können Sie die Anfrage abbrechen:

request.abort();

Sie können ein Array verwenden, das alle ausstehenden Ajax-Anforderungen verfolgt und sie bei Bedarf abbricht.

Darin Dimitrov
quelle
THXs, ich habe eine FLAG hinzugefügt, weil ich mehrere Anfragen gleichzeitig verwendet habe
jcho360
Hier ist ein einfaches Arbeitsbeispiel: stackoverflow.com/a/42312101/3818394
Dharmesh Patel
Ich habe einen Ajax-Aufruf in der Funktion. Wie kann ich ihn abbrechen?
Kalariya_M
Die Variable muss als global deklariert werden, um von einer anderen Funktion aus auf sie zugreifen zu können, wenn ein Ajax-Aufruf ausgeführt wird. Beispiel: Ein Upload-Vorgang mit mehreren Dateien.
Clain Dsilva
180

Mit dem folgenden Snippet können Sie eine Liste ( Pool ) von Anforderungen verwalten und diese bei Bedarf abbrechen. Am besten in <HEAD>Ihrem HTML-Code platzieren, bevor andere AJAX-Aufrufe getätigt werden.

<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
quelle
2
@mkmurray - bei der Initialisierung in IE8 scheine ich zu bekommen Object doesn't support property or method 'indexOf'? Ich vermute, es könnte stackoverflow.com/a/2608601/181971 sein oder einfach zu stackoverflow.com/a/2608618/181971 wechseln ?
Tim
3
@grr ist richtig, sehen Sie seine Antwort und überprüfen Sie die Dokumente auf ajaxSetup .
Kzfabi
@Tim - wie Steven vorgeschlagen hat, anstelle von var index = $ .xhrPool.indexOf (jqXHR); Verwenden Sie: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Es zeigt TypeError: jqXHR.abort ist keine Funktion für mich. :(
Shesha
Es gibt einen kleinen logischen Fehler in der abortAll-Methode, der hier in dieser Antwort behoben wird. Stackoverflow.com/a/45500874/1041341
Sarin JS
122

Die Verwendung von ajaxSetup ist nicht korrekt , wie auf der Dokumentseite angegeben. Es werden nur Standardeinstellungen eingerichtet, und wenn einige Anforderungen diese überschreiben, kommt es zu einem Durcheinander.

Ich bin viel zu spät zur Party, aber nur zum späteren Nachschlagen, wenn jemand nach einer Lösung für das gleiche Problem sucht, hier ist mein Versuch, inspiriert von und weitgehend identisch mit den vorherigen Antworten, aber vollständiger

// 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
quelle
Wie ruft man die abort () -Methode von anderen Funktionen auf?
Stan James
Abbruch ist eine Funktion, keine Methode. Sie rufen es normalerweise innerhalb derselben Kapselung auf. Wenn Sie es außerhalb der Kapselung verwenden müssen, können Sie das "var" vor dem Funktionsnamen entfernen und es wird zu einer global verfügbaren Funktion
Trey
Hallo, könnte jemand erklären, wann r undefiniert sein wird?
Varun
36

Folgendes verwende ich derzeit, um dies zu erreichen.

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

Hinweis: _.jeder von underscore.js ist vorhanden, aber offensichtlich nicht erforderlich. Ich bin nur faul und möchte es nicht in $ .each () ändern. 8P

Andy Ferra
quelle
2
Ich habe eine leicht modifizierte Lösung, die großartig funktioniert und die ich gerade veröffentlichen werde.
Mkmurray
7
Dadurch geht Speicher verloren. aboutAllsollte die Elemente aus dem Array entfernen. Wenn eine Anfrage abgeschlossen ist, sollte sie sich selbst aus der Liste entfernen.
Behrang Saeedzadeh
5
@BehrangSaeedzadeh Du hättest dann auch eine verbesserte Version posten sollen.
Mattsven
19

Geben Sie jeder xhr-Anforderung eine eindeutige ID und speichern Sie die Objektreferenz vor dem Senden in einem Objekt. Löschen Sie die Referenz, nachdem eine xhr-Anforderung abgeschlossen wurde.

So stornieren Sie alle Anfragen jederzeit:

$.ajaxQ.abortAll();

Gibt die eindeutigen IDs der stornierten Anforderung zurück. Nur zu Testzwecken.

Arbeitsfunktion:

$.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;
    }
  };

})();

Gibt ein Objekt mit einer einzelnen Funktion zurück, mit dem bei Bedarf weitere Funktionen hinzugefügt werden können.

refik
quelle
17

Ich fand es zu einfach für mehrere Anfragen.

Schritt 1: Definieren Sie eine Variable oben auf der Seite:

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

Schritt 2: set beforeSend in allen Ajax-Anfragen:

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

Schritt 3: Verwenden Sie es, wo immer Sie es benötigen:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Dharmesh Patel
quelle
Dadurch geht Speicher verloren, genau wie bei stackoverflow.com/a/6618288/1772379 und aus genau den gleichen Gründen.
Ben Johnson
Wirklich schreckliche Art, JavaScript zu schreiben.
Ozil
1
Möglicherweise können Sie am Ende das xhrPool-Array löschen / leeren
space earth
6

Ich habe die Antwort von mkmurray und SpYk3HH oben erweitert, damit xhrPool.abortAll alle ausstehenden Anforderungen einer bestimmten URL abbrechen kann :

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

Die Verwendung ist dieselbe, außer dass abortAll jetzt optional eine URL als Parameter akzeptieren kann und nur ausstehende Aufrufe dieser URL abbricht

Kofifus
quelle
5

Ich hatte einige Probleme mit Andys Code, aber es gab mir einige großartige Ideen. Das erste Problem war, dass wir alle erfolgreich abgeschlossenen jqXHR-Objekte entfernen sollten. Ich musste auch die abortAll-Funktion ändern. Hier ist mein endgültiger Arbeitscode:

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

Die ajaxComplete () -Methode hat mir nicht gefallen. Egal wie ich versucht habe, .ajaxSetup zu konfigurieren, es hat nicht funktioniert.

der Hampster
quelle
7
Ich denke, Sie rufen Pop möglicherweise auf falsche Anfrage an, wenn sie nicht in einer bestimmten Reihenfolge ausgeführt werden.
Jjmontes
1
Ja, Sie möchten Slice statt Pop machen. Ich habe eine leicht modifizierte Lösung, die ich veröffentlichen werde.
Mkmurray
4

Ich habe den Code aktualisiert, damit er für mich funktioniert

$.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
quelle
4

Werfen Sie meinen Hut in. Angebote abortund removeMethoden gegen das xhrPoolArray, und ist nicht anfällig für Probleme mit ajaxSetupÜberschreibungen.

/**
 * 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
quelle
2

Machen Sie einen Pool aller Ajax-Anfragen und brechen Sie sie ab .....

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

Besser unabhängigen Code verwenden .....

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

Genauso wichtig: Angenommen, Sie möchten sich abmelden und generieren neue Anforderungen mit Timern: Weil die Sitzungsdaten mit jedem neuen Bootstrap erneuert werden (vielleicht können Sie sagen, dass ich über Drupal spreche, aber dies kann jede Site sein, die Sitzungen verwendet). Ich musste alle meine Skripte mit einem Suchen und Ersetzen durchgehen, weil in verschiedenen Fällen eine Menge Dinge ausgeführt wurden: globale Variablen oben:

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');
}
Gute Nachrichten
quelle
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));

Wenn Sie die gesamte Ajax-Anfrage abbrechen möchten, müssen Sie nur diese Leitung anrufen

Request.AbortAll()
Omid Matouri
quelle
-2

Es gibt eine Dummy-Lösung, mit der ich alle Ajax-Anfragen abbreche. Diese Lösung lädt die gesamte Seite neu. Diese Lösung ist gut, wenn Sie nicht jeder Ajax-Anforderung eine ID zuweisen möchten und wenn Sie Ajax-Anforderungen innerhalb der for-Schleife stellen. Dadurch wird sichergestellt, dass alle Ajax-Anforderungen beendet werden.

location.reload();
ASammour
quelle
-3

So schließen Sie dies bei jedem Klick an (nützlich, wenn Ihre Seite viele AJAX-Anrufe tätigt und Sie versuchen, weg zu navigieren).

$ ->
    $.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.
quelle