Detenga todas las solicitudes de ajax activas en jQuery

216

Tengo un problema, cuando envío un formulario, todas las solicitudes activas de ajax fallan, y eso desencadena un evento de error.

¿Cómo detener todas las solicitudes activas de ajax en jQuery sin un evento de error de trigerring?

Umpirsky
fuente

Respuestas:

273

Cada vez que crea una solicitud ajax, puede usar una variable para almacenarla:

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

Entonces puedes abortar la solicitud:

request.abort();

Puede utilizar una matriz que rastrea todas las solicitudes pendientes de ajax y abortarlas si es necesario.

Darin Dimitrov
fuente
THXs, agregué una BANDERA porque usé varias solicitudes al mismo tiempo
jcho360
Aquí hay un ejemplo de trabajo simple: stackoverflow.com/a/42312101/3818394
Dharmesh patel
Tengo una llamada ajax en función, ¿cómo puedo cancelarla?
Kalariya_M
La variable debe declararse global para acceder desde otra función cuando hay una llamada ajax en curso. ejemplo: un proceso de carga de múltiples archivos.
Clain Dsilva
180

El siguiente fragmento le permite mantener una lista ( grupo ) de solicitudes y cancelarlas todas si es necesario. Lo mejor es colocarlo en <HEAD>su html, antes de realizar cualquier otra llamada 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
fuente
2
@mkmurray - en la inicialización en IE8 parece que tengo Object doesn't support property or method 'indexOf'? Sospecho que podría ser stackoverflow.com/a/2608601/181971 o tal vez simplemente cambiar a stackoverflow.com/a/2608618/181971 ?
Tim
3
@grr tiene razón, vea su respuesta y verifique los documentos para ajaxSetup .
kzfabi
@Tim: como sugirió Steven, en lugar de var index = $ .xhrPool.indexOf (jqXHR); use: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Muestra TypeError: jqXHR.abort no es una función para mí. :(
Shesha
Hay un ligero error lógico en el método abortAll, que se corrige aquí en esta respuesta stackoverflow.com/a/45500874/1041341
Sarin JS
122

El uso de ajaxSetup no es correcto , como se señala en su página de documentación. Solo configura los valores predeterminados, y si algunas solicitudes los anulan, habrá un desastre.

Llego tarde a la fiesta, pero solo para referencia futura si alguien está buscando una solución al mismo problema, aquí está mi intento, inspirado y en gran parte idéntico a las respuestas anteriores, pero más 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
fuente
¿Cómo se llama al método abort () desde otras funciones?
Stan James
abortar es una función, no un método. normalmente lo llama desde dentro de la misma encapsulación, si necesita usarlo fuera de la encapsulación puede eliminar la "var" antes del nombre de la función y se convertirá en una función disponible globalmente
Trey
Hola, ¿alguien podría explicar cuándo r estará indefinido?
Varun
36

Esto es lo que estoy usando actualmente para lograr eso.

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

Nota: _.each of underscore.js está presente, pero obviamente no es necesario. Solo soy flojo y no quiero cambiarlo a $ .each (). 8P

Andy Ferra
fuente
2
Tengo una solución ligeramente modificada que funciona muy bien y que estoy a punto de publicar.
mkmurray
77
Esto pierde memoria. aboutAlldebería eliminar los elementos de la matriz. Además, cuando finaliza una solicitud, debe eliminarse de la lista.
Behrang Saeedzadeh
55
@BehrangSaeedzadeh También debería haber publicado una versión mejorada.
mattsven
19

Dele a cada solicitud xhr una identificación única y almacene la referencia del objeto en un objeto antes de enviarlo. Elimine la referencia después de que se complete una solicitud xhr.

Para cancelar toda solicitud en cualquier momento:

$.ajaxQ.abortAll();

Devuelve los identificadores únicos de la solicitud cancelada. Solo con fines de prueba.

Función de trabajo:

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

})();

Devuelve un objeto con una sola función que se puede usar para agregar más funcionalidad cuando sea necesario.

refik
fuente
17

Lo encontré demasiado fácil para múltiples solicitudes.

Paso 1: define una variable en la parte superior de la página:

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

Paso 2: establecer antes de enviar en todas las solicitudes ajax:

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

Paso 3: úsalo donde lo necesites:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Dharmesh patel
fuente
Esto pierde memoria, al igual que stackoverflow.com/a/6618288/1772379 , y precisamente por las mismas razones.
Ben Johnson
Una forma realmente horrible de escribir JavaScript.
Ozil
1
puede estar al final, puede borrar / vaciar la matriz xhrPool
space earth
6

Extendí mkmurray y la respuesta SpYk3HH anterior para que xhrPool.abortAll pueda abortar todas las solicitudes pendientes de una URL dada :

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

El uso es el mismo, excepto que abortAll ahora puede aceptar opcionalmente una url como parámetro y cancelará solo las llamadas pendientes a esa url

kofifus
fuente
5

Tuve algunos problemas con el código de Andy, pero me dio algunas ideas geniales. El primer problema fue que deberíamos extraer cualquier objeto jqXHR que se complete con éxito. También tuve que modificar la función abortAll. Aquí está mi código de trabajo final:

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

No me gustó la forma de hacer las cosas ajaxComplete (). No importa cómo intenté configurar .ajaxSetup, no funcionó.

el hámster
fuente
77
¿Creo que puede estar llamando pop en la solicitud incorrecta si no se completan en un orden en particular?
jjmontes
1
Sí, quieres hacer una rebanada en lugar de pop. Tengo una solución ligeramente modificada que estoy a punto de publicar.
mkmurray
4

He actualizado el código para que funcione para mí.

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

Lanzando mi sombrero. Ofertas aborty removemétodos contra la xhrPoolmatriz, y no es propenso a problemas con las ajaxSetupanulaciones.

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

Haga un grupo de todas las solicitudes de ajax y abortarlas .....

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

Mejor usar código independiente .....

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

Igual de importante: digamos que desea cerrar sesión y está generando nuevas solicitudes con temporizadores: porque los datos de la sesión se renuevan con cada arranque nuevo (tal vez pueda decir que estoy hablando de Drupal, pero este podría ser cualquier sitio que use sesiones). Tuve que revisar todos mis scripts con una búsqueda y reemplazo, porque tenía un montón de cosas ejecutándose en diferentes casos: variables globales en la parte superior:

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');
}
Buenas noticias
fuente
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));

cada vez que desee cancelar toda la solicitud de ajax, solo necesita llamar a esta línea

Request.AbortAll()
Omid Matouri
fuente
-2

Hay una solución ficticia que la uso para cancelar todas las solicitudes de ajax. Esta solución es volver a cargar toda la página. Esta solución es buena si no le gusta asignar una ID a cada solicitud ajax, y si realiza solicitudes ajax dentro de for-loop. Esto asegurará que se eliminen todas las solicitudes de ajax.

location.reload();
ASammour
fuente
-3

Aquí le mostramos cómo conectar esto con cualquier clic (útil si su página está haciendo muchas llamadas AJAX y está tratando de 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.
fuente