Abortar solicitudes Ajax usando jQuery

1827

Con jQuery, ¿cómo puedo cancelar / cancelar una solicitud de Ajax de la que aún no he recibido la respuesta?

lukewm
fuente
2
Tal vez he entendido mal la pregunta, pero ¿no podrías simplemente usarla $.ajaxStop?
Luke Madhanga el
17
@LukeMadhanga; Creo que ajaxStopsolo detecta cuando se completan todas las solicitudes AJAX, no detiene una solicitud. En mi experiencia, se usaría así: $(document).ajaxStop(function(){alert("All done")}). Usar .abort()es la mejor opción.
TheCarver

Respuestas:

1744

La mayoría de los métodos jQuery Ajax devuelven un objeto XMLHttpRequest (o el equivalente), por lo que puede usarlo abort().

Ver la documentación:

var xhr = $.ajax({
    type: "POST",
    url: "some.php",
    data: "name=John&location=Boston",
    success: function(msg){
       alert( "Data Saved: " + msg );
    }
});

//kill the request
xhr.abort()

ACTUALIZACIÓN: A partir de jQuery 1.5, el objeto devuelto es un contenedor para el objeto XMLHttpRequest nativo llamado jqXHR. Este objeto parece exponer todas las propiedades y métodos nativos, por lo que el ejemplo anterior aún funciona. Ver el objeto jqXHR (documentación de la API jQuery).

ACTUALIZACIÓN 2: a partir de jQuery 3, el método ajax ahora devuelve una promesa con métodos adicionales (como abortar), por lo que el código anterior aún funciona, aunque el objeto que se devuelve ya no es un xhr. Vea el blog 3.0 aquí .

ACTUALIZACIÓN 3 : xhr.abort()todavía funciona en jQuery 3.x. No asuma que la actualización 2 es correcta. Más información sobre el repositorio jQuery Github .

meouw
fuente
12
Es como hacer clic en el botón 'detener' en su navegador. Se cancela la solicitud. Luego puede reutilizar el mismo objeto XHR para otra solicitud.
meouw el
65
@brad Desafortunadamente, abortno cierra una conexión establecida con el servidor, por successlo que aún se llamará. Esto es muy problemático para implementaciones de Comet con encuestas largas.
pepkin88
66
@ErvWalter Puede enviar otra solicitud que cancele la anterior.
Asad Saeeduddin
8
En mis pruebas, la solicitud se cancela en el navegador, pero el método .fail () se invoca con un jqXHR, estado = 0, y jqXHR, statusMessage = "abortar"
BJ Safdie
99
.abort()todavía funciona para mí en jQuery 3.2.1. Este comentario en un problema relacionado de Github por un miembro del equipo central de jQuery parece implicar que esta respuesta es incorrecta y que .abort() no se eliminó.
alarmante
117

No puede recuperar la solicitud, pero puede establecer un valor de tiempo de espera después del cual se ignorará la respuesta. Ver esta página para ver las opciones de jquery AJAX. Creo que se llamará a su devolución de llamada de error si se excede el período de tiempo de espera. Ya hay un tiempo de espera predeterminado en cada solicitud de AJAX.

También puede utilizar el aborto () método en el objeto solicitud, pero, mientras que hará que el cliente deje de detectar el evento, se puede probablemente no va a detener el servidor de procesarlo.

tvanfosson
fuente
74

Es un asíncrono solicitud , lo que significa que una vez que se envía, está disponible.

En caso de que su servidor esté iniciando una operación muy costosa debido a la solicitud de AJAX, lo mejor que puede hacer es abrir su servidor para escuchar las solicitudes de cancelación y enviar una solicitud de AJAX por separado notificando al servidor que deje de hacer lo que esté haciendo.

De lo contrario, simplemente ignore la respuesta AJAX.

Yuval Adam
fuente
48
En este contexto, asíncrono simplemente significa que la solicitud no interrumpe el flujo del script. Los navegadores ahora tienen la capacidad de abortar la solicitud antes de que se complete la solicitud.
ElephantHunter
44
¿Cómo podemos enviar una solicitud de cancelación al servidor? No entiendo cómo el servidor sabrá qué solicitud para detener el procesamiento. ¿Podrías dar un ejemplo? Gracias.
Lucky Soni
3
@LuckySoni, Elephanthunter solo está discutiendo del lado del cliente. El servidor no se verá afectado por una solicitud .abort
Kloar
44
@Kloar, si el servidor aún no recibe la solicitud (por ejemplo, solicitudes multiparte grandes), el cliente puede cerrar el socket y el servidor se verá afectado.
blanco
44
PHP comprueba las solicitudes canceladas automáticamente y también finaliza automáticamente. ver php.net/manual/en/function.ignore-user-abort.php
hanshenrik
68

Guarde las llamadas que realiza en una matriz, luego llame a xhr.abort () en cada una.

GRAN CUEVA: puede cancelar una solicitud, pero eso es solo del lado del cliente. El lado del servidor aún podría estar procesando la solicitud. Si está utilizando algo como PHP o ASP con datos de sesión, los datos de la sesión se bloquean hasta que el ajax haya finalizado. Entonces, para permitir que el usuario continúe navegando por el sitio web, debe llamar a session_write_close (). Esto guarda la sesión y la desbloquea para que continúen otras páginas que esperan continuar. Sin esto, varias páginas pueden estar esperando que se elimine el bloqueo.

Tei
fuente
Como siempre cancelas el anterior, ¿no puedes hacer eso siempre? (y no es necesario usar una matriz)
polaridad
60

Las solicitudes AJAX pueden no completarse en el orden en que se iniciaron. En lugar de abortar, puede optar por ignorar todas las respuestas AJAX, excepto la más reciente:

  • Crea un contador
  • Incremente el contador cuando inicie la solicitud AJAX
  • Use el valor actual del contador para "sellar" la solicitud
  • En la devolución de llamada exitosa, compare el sello con el contador para verificar si fue la solicitud más reciente

Esquema aproximado del código:

var xhrCount = 0;
function sendXHR() {
    // sequence number for the current invocation of function
    var seqNumber = ++xhrCount;
    $.post("/echo/json/", { delay: Math.floor(Math.random() * 5) }, function() {
        // this works because of the way closures work
        if (seqNumber === xhrCount) {
            console.log("Process the response");
        } else {
            console.log("Ignore the response");
        }
    });
}
sendXHR();
sendXHR();
sendXHR();
// AJAX requests complete in any order but only the last 
// one will trigger "Process the response" message

Demostración en jsFiddle

Salman A
fuente
Debido a las advertencias de cancelar una solicitud XHR (ver otros comentarios en esta página), esta es probablemente la mejor y más simple opción.
Quinn Commandado
41

Simplemente tuvimos que solucionar este problema y probamos tres enfoques diferentes.

  1. cancela la solicitud como lo sugiere @meouw
  2. ejecuta todas las solicitudes pero solo procesa el resultado del último envío
  3. evita nuevas solicitudes mientras haya otra pendiente

var Ajax1 = {
  call: function() {
    if (typeof this.xhr !== 'undefined')
      this.xhr.abort();
    this.xhr = $.ajax({
      url: 'your/long/running/request/path',
      type: 'GET',
      success: function(data) {
        //process response
      }
    });
  }
};
var Ajax2 = {
  counter: 0,
  call: function() {
    var self = this,
      seq = ++this.counter;
    $.ajax({
      url: 'your/long/running/request/path',
      type: 'GET',
      success: function(data) {
        if (seq === self.counter) {
          //process response
        }
      }
    });
  }
};
var Ajax3 = {
  active: false,
  call: function() {
    if (this.active === false) {
      this.active = true;
      var self = this;
      $.ajax({
        url: 'your/long/running/request/path',
        type: 'GET',
        success: function(data) {
          //process response
        },
        complete: function() {
          self.active = false;
        }
      });
    }
  }
};
$(function() {
  $('#button').click(function(e) {
    Ajax3.call();
  });
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="button" type="button" value="click" />

En nuestro caso, decidimos usar el enfoque n. ° 3, ya que produce menos carga para el servidor. Pero no estoy 100% seguro si jQuery garantiza la llamada del método .complete (), esto podría producir una situación de punto muerto. En nuestras pruebas no pudimos reproducir tal situación.

oofante
fuente
36

Siempre es una buena práctica hacer algo como esto.

var $request;
if ($request != null){ 
    $request.abort();
    $request = null;
}

$request = $.ajax({
    type : "POST", //TODO: Must be changed to POST
    url : "yourfile.php",
    data : "data"
    }).done(function(msg) {
        alert(msg);
    });

Pero es mucho mejor si marca una instrucción if para verificar si la solicitud ajax es nula o no.

Tharindu Kumara
fuente
2
También verifico si una solicitud ya se está ejecutando, pero uso un booleano, ya que es más ligero.
Zesty
15

Solo llama a xhr. abort () ya sea un objeto jquery ajax o un objeto XMLHTTPRequest nativo.

ejemplo:

//jQuery ajax
$(document).ready(function(){
    var xhr = $.get('/server');
    setTimeout(function(){xhr.abort();}, 2000);
});

//native XMLHTTPRequest
var xhr = new XMLHttpRequest();
xhr.open('GET','/server',true);
xhr.send();
setTimeout(function(){xhr.abort();}, 2000);
cuixiping
fuente
13

Estaba haciendo una solución de búsqueda en vivo y necesitaba cancelar las solicitudes pendientes que pueden haber tardado más que la última / más reciente.

En mi caso usé algo como esto:

//On document ready
var ajax_inprocess = false;

$(document).ajaxStart(function() {
ajax_inprocess = true;
});

$(document).ajaxStop(function() {
ajax_inprocess = false;
});

//Snippet from live search function
if (ajax_inprocess == true)
{
    request.abort();
}
//Call for new request 
Porra
fuente
12

Como han notado muchas personas en el hilo, solo porque la solicitud se cancela en el lado del cliente, el servidor aún procesará la solicitud. Esto crea una carga innecesaria en el servidor porque está haciendo un trabajo que hemos dejado de escuchar en el front-end.

El problema que estaba tratando de resolver (que otros también pueden encontrar) es que cuando el usuario ingresó información en un campo de entrada, quise disparar una solicitud de un tipo de sensación de Google Instant.

Para evitar disparar solicitudes innecesarias y mantener la rapidez del front-end, hice lo siguiente:

var xhrQueue = [];
var xhrCount = 0;

$('#search_q').keyup(function(){

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

        if (xhrCount === xhrQueue.length) {
            // Fire Your XHR //
        }

    }, 150);

});

Básicamente, esto enviará una solicitud cada 150 ms (una variable que puede personalizar para sus propias necesidades). Si usted está teniendo problemas para entender qué es exactamente lo que está pasando aquí, registrar xhrCounty xhrQueuea la consola justo antes del bloque if.

brianrea
fuente
11

Simplemente use ajax.abort (), por ejemplo, podría cancelar cualquier solicitud de ajax pendiente antes de enviar otra como esta

//check for existing ajax request
if(ajax){ 
 ajax.abort();
 }
//then you make another ajax request
$.ajax(
 //your code here
  );
Joecoder001
fuente
11

Puede abortar cualquier llamada continua ajax usando esto

<input id="searchbox" name="searchbox" type="text" />

<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>

<script type="text/javascript">
     var request = null;
        $('#searchbox').keyup(function () {
            var id = $(this).val();
            request = $.ajax({
                type: "POST", //TODO: Must be changed to POST
                url: "index.php",
                data: {'id':id},
                success: function () {

                },
                beforeSend: function () {
                    if (request !== null) {
                        request.abort();
                    }
                }
            });
        });

</script>
Soubhagya Kumar Barik
fuente
10

no hay una manera confiable de hacerlo, y ni siquiera lo intentaría, una vez que la solicitud esté en camino; La única forma de reaccionar razonablemente es ignorar la respuesta.

en la mayoría de los casos, puede suceder en situaciones como: un usuario hace clic con demasiada frecuencia en un botón que activa muchos XHR consecutivos, aquí tiene muchas opciones, ya sea bloquear el botón hasta que se devuelva XHR, o incluso no activar un nuevo XHR mientras otro se está ejecutando insinuando que el usuario se recueste o descarte cualquier respuesta XHR pendiente que no sea la reciente.

comeGetSome
fuente
7

El siguiente código muestra el inicio y el aborto de una solicitud de Ajax:

function libAjax(){
  var req;
  function start(){

  req =    $.ajax({
              url: '1.php',
              success: function(data){
                console.log(data)
              }
            });

  }

  function stop(){
    req.abort();
  }

  return {start:start,stop:stop}
}

var obj = libAjax();

 $(".go").click(function(){


  obj.start();


 })



 $(".stop").click(function(){

  obj.stop();


 })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" class="go" value="GO!" >
   <input type="button" class="stop" value="STOP!" >
zloctb
fuente
55
Proporcione una explicación de cómo esto resuelve la pregunta. Esto ayudará al OP y a otros futuros buscadores.
SnareChops
5

Tuve el problema de sondear y una vez que se cerró la página, la encuesta continuó, por lo que en mi causa un usuario se perdería una actualización, ya que se configuró un valor mysql durante los siguientes 50 segundos después del cierre de la página, aunque eliminé la solicitud de ajax, me di cuenta de que usar $ _SESSION para establecer una var no se actualizará en la encuesta hasta que finalice y comience una nueva, así que lo que hice fue establecer un valor en mi base de datos como 0 = fuera de página, mientras estoy sondeo, consulto esa fila y devuelvo falso; cuando es 0, ya que las consultas en el sondeo obtendrán valores actuales obviamente ...

Espero que esto haya ayudado

Marcus
fuente
5

Si xhr.abort(); provoca la recarga de la página,

Luego puede configurar onreadystatechangeantes de abortar para evitar:

// ↓ prevent page reload by abort()
xhr.onreadystatechange = null;
// ↓ may cause page reload
xhr.abort();
vikyd
fuente
4

He compartido una demostración que muestra cómo cancelar una solicitud AJAX, si los datos no se devuelven del servidor dentro de un tiempo de espera predefinido.

HTML:

<div id="info"></div>

CÓDIGO JS:

var isDataReceived= false, waitTime= 1000; 
$(function() {
    // Ajax request sent.
     var xhr= $.ajax({
      url: 'http://api.joind.in/v2.1/talks/10889',
      data: {
         format: 'json'
      },     
      dataType: 'jsonp',
      success: function(data) {      
        isDataReceived= true;
        $('#info').text(data.talks[0].talk_title);        
      },
      type: 'GET'
   });
   // Cancel ajax request if data is not loaded within 1sec.
   setTimeout(function(){
     if(!isDataReceived)
     xhr.abort();     
   },waitTime);   
});
ganesh
fuente
1
$.ajaxproporciona una timeoutopción para que no necesite escribir la suya. Simplemente use ..., data: {...}, timeout: waitTime,....
Bram Vanroy