Pare todas as solicitações de ajax ativas no jQuery

216

Eu tenho um problema, ao enviar um formulário, todas as solicitações de ajax ativas falham e isso dispara um evento de erro.

Como parar todas as solicitações de ajax ativas no jQuery sem evento de erro de trigerring?

umpirsky
fonte

Respostas:

273

Toda vez que você cria uma solicitação ajax, pode usar uma variável para armazená-la:

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

Então você pode abortar a solicitação:

request.abort();

Você pode usar uma matriz para acompanhar todas as solicitações de ajax pendentes e abortá-las, se necessário.

Darin Dimitrov
fonte
Thxs, I adicionou-se uma FLAG porque I utilizados múltiplos pedido ao mesmo tempo
jcho360
aqui é exemplo de trabalho simples: stackoverflow.com/a/42312101/3818394
Dharmesh Patel
Eu tenho a função de chamada ajax como posso abortá-lo?
Kalariya_M
A variável deve ser declarada global para acessá-la de outra função quando uma chamada ajax estiver em andamento. exemplo: um processo de upload de vários arquivos.
Clain Dsilva
180

O fragmento a seguir permite manter uma lista ( pool ) de solicitações e interromper todas, se necessário. É melhor colocar no <HEAD>html antes que outras chamadas AJAX sejam feitas.

<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
fonte
2
@mkmurray - sobre a initalização no IE8 parece que eu entendo Object doesn't support property or method 'indexOf'? Eu suspeito que pode ser stackoverflow.com/a/2608601/181971 ou talvez simplesmente trocar para stackoverflow.com/a/2608618/181971 ?
Tim
3
@grr está certo, veja a resposta dele e verifique os documentos quanto ao ajaxSetup .
Kzfabi
@ Tim - como Steven sugeriu, em vez de var index = $ .xhrPool.indexOf (jqXHR); use: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Mostra TypeError: jqXHR.abort não é uma função para mim. :(
Shesha
Existe um pequeno erro lógico no método abortAll, que é corrigido aqui nesta resposta stackoverflow.com/a/45500874/1041341
Sarin JS
122

O uso do ajaxSetup não está correto , conforme observado em sua página de documento. Ele apenas configura os padrões e, se alguns pedidos os substituírem, haverá uma bagunça.

Estou muito atrasado para a festa, mas apenas para referência futura, se alguém estiver procurando uma solução para o mesmo problema, aqui está minha chance, inspirado e amplamente idêntico às respostas anteriores, mas mais completo

// 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
fonte
Como alguém chama o método abort () de outras funções?
Stan James
abortar é uma função, não um método. você chamá-lo de dentro do mesmo encapsulamento normalmente, se você precisar usá-lo fora do encapsulamento você pode remover o "var" antes do nome da função e ele se tornará um funciton disponível globalmente
Trey
Oi, alguém poderia explicar quando r será indefinido?
Varun
36

Aqui está o que estou usando atualmente para fazer isso.

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

Nota: _.each de underscore.js está presente, mas obviamente não é necessário. Sou apenas preguiçoso e não quero alterá-lo para $ .each (). 8P

Andy Ferra
fonte
2
Eu tenho uma solução ligeiramente modificada que funciona muito bem e estou prestes a postar.
Mckurray
7
Isso vaza memória. aboutAlldeve remover os elementos da matriz. Além disso, quando uma solicitação é concluída, ela deve se remover da lista.
Behrang Saeedzadeh
5
@BehrangSaeedzadeh Você também deveria ter postado uma versão melhorada.
mattsven
19

Dê a cada solicitação xhr um ID exclusivo e armazene a referência do objeto em um objeto antes de enviá-lo. Exclua a referência depois que uma solicitação xhr for concluída.

Para cancelar todas as solicitações a qualquer momento:

$.ajaxQ.abortAll();

Retorna os IDs exclusivos da solicitação cancelada. Apenas para fins de teste.

Função de trabalho:

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

})();

Retorna um objeto com função única que pode ser usada para adicionar mais funcionalidades quando necessário.

refik
fonte
17

Achei muito fácil para várias solicitações.

Etapa 1: defina uma variável no topo da página:

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

step2: configure beforeSend em todas as solicitações de ajax:

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

step3: use-o sempre que necessário:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Dharmesh patel
fonte
Isso vaza memória, assim como o stackoverflow.com/a/6618288/1772379 , e exatamente pelos mesmos motivos.
217 Ben Ben Johnson
Maneira realmente horrível de escrever JavaScript.
Ozil
1
pode estar no final, você pode limpar / esvaziar a matriz xhrPool
space earth
6

Estendi a resposta mkmurray e SpYk3HH acima para que xhrPool.abortAll possa interromper todas as solicitações pendentes de um determinado 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;
});

O uso é o mesmo, exceto que abortAll agora pode aceitar opcionalmente um URL como parâmetro e cancelará apenas as chamadas pendentes para esse URL

kofifus
fonte
5

Eu tive alguns problemas com o código de Andy, mas isso me deu ótimas idéias. O primeiro problema foi que devemos remover quaisquer objetos jqXHR que foram concluídos com êxito. Eu também tive que modificar a função abortAll. Aqui está o meu código de trabalho final:

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

Não gostei da maneira ajaxComplete () de fazer as coisas. Não importa como eu tentei configurar o .ajaxSetup, ele não funcionou.

o Hampster
fonte
7
Eu acho que você pode estar ligando pop na solicitação errada se eles não forem concluídos em uma ordem específica?
jjmontes
1
Sim, você quer fatiar em vez de pop. Eu tenho uma solução ligeiramente modificada que estou prestes a postar.
Mckurray
4

Atualizei o código para que ele funcione para mim

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

Jogando meu chapéu. Ofertas aborte removemétodos contra a xhrPoolmatriz e não é propenso a problemas com ajaxSetupsubstituições.

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

Faça um pool de todas as solicitações de ajax e aborte-as ...

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

Melhor usar código independente .....

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

Tão importante quanto: digamos que você deseja fazer logoff e está gerando novas solicitações com temporizadores: porque os dados da sessão são renovados a cada nova inicialização (talvez você possa dizer que estou falando do Drupal, mas esse pode ser qualquer site que utilize sessões) .. Eu tive que passar por todos os meus scripts com uma pesquisa e substituição, porque eu tinha uma tonelada de coisas sendo executadas em diferentes casos: variáveis ​​globais no topo:

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');
}
Boas notícias
fonte
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));

sempre que você quiser abortar toda a solicitação ajax, basta ligar para esta linha

Request.AbortAll()
Omid Matouri
fonte
-2

Existe uma solução fictícia que eu a uso para abortar todas as solicitações de ajax. Esta solução é recarregar a página inteira. Essa solução é boa se você não gosta de atribuir um ID a cada solicitação ajax e se faz solicitações ajax dentro do loop for. Isso garantirá que todas as solicitações de ajax sejam eliminadas.

location.reload();
ASammour
fonte
-3

Veja como conectar isso a qualquer clique (útil se a sua página estiver fazendo muitas chamadas AJAX e você estiver tentando navegar).

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