Skip to content

Bloquea el doble envío de peticiones AJAX con jQuery

18 marzo 2012

En esta entrada vamos a proponer un método adicional que nos permita bloquear el envío de una misma petición AJAX cuando aún no hemos recibido la respuesta de una petición anterior. El método que vamos a ver aquí no pretendo que sea el mejor ni el más infalible, pero puede resultarnos útil en determinadas ocasiones y además nos dará pie a conocer una función muy util de jQuery denominada: data()

El método que os presento está basado en la técnica utilizada para proveer de sincronización a los diferentes procesos dentro de un sistema de procesamiento paralelo, conocida como Semáforo. Veréis que su uso es muy simple y sencillo y resulta terriblemente eficiente en determinadas situaciones en las que debemos impedir que los clicks que realicen los usuarios sobre el botón de envío de nuestras peticiones AJAX (en los submit de los formularios por ejemplo) provoquen que se envíe la misma petición varias veces.

Pero primero, vamos a ver un poco de teoría sobre la función data() de jQuery.

Función data(), jQuery

La función data() de la librería jQuery, nos va a permitir asociar datos a los diferentes nodos del árbol DOM. Por supuesto, también nos va a permitir consultar si un determinado nodo (un div, por ejemplo) contiene algún dato asociado previamente con esta función y obtener el valor almacenado.

La gran potencia que tiene esta función se basa en que no sólo podremos almacenar datos de tipo String, sino que podremos almacenar diferentes tipos de datos como: booleanos, valores numéricos, objetos javascript, arrays… Los datos que almacenemos lo harán en forma de pares {clave, valor} de modo que podremos recuperar el valor que nos interese simplemente preguntando por su clave.

Podremos asociar múltiples datos a un elemento determinado y consultarlos en el momento en el que nos haga falta:

$('body').data('author_firstname','Frodo');
$('body').data('author_lastname', 'Bolson');

Podemos asociarlos también en formato array:

$('body').data('author_info',{firstname: 'Frodo', lastname:'Bolson'});

Para consultar si nuestro nodo del árbol DOM contiene datos asociados, invocaremos a la función data() con un único parámetro que será la clave de la que nos interesa obtener su valor:

$('body').data('author_firstname');

Si la clave no ha sido definida previamente, el resultado de la llamada será undefined.

O si habíamos almacenado los datos en un array:

$('body').data('author_info').firstname;

Si el selector de jQuery que utilizamos para seleccionar el nodo al que asociaremos los datos, devuelve una selección de elementos en lugar de un solo elemento como hemos visto aquí, se asociarán los datos a todos los elementos que se encuentren dentro de esa selección. Por ejemplo:

$('div').data('valor', 10);

Asociará el par {‘valor’, 10} a todos los divs que estén definidos en nuestro árbol DOM.

Para consultar si un nodo tiene un valor asociado a una determinada clave con la función data(), podemos hacer lo siguiente:

if ($('body').data('authorinfo')){
 //Leemos el dato
}else{
 //Establecemos el valor por ejemplo
}

Para eliminar un dato asociado a un nodo, utilizaremos la función: removeData( key );

$('body').removeData('authorinfo');

Si utilizamos removeData() sin parámetros, eliminará todos los datos asociados al nodo en cuestión:

$('body').removeData();

Que sí, venga, que si quiero conocer en profundidad la función data() ya consultaré su documentación y su API, muéstrame el ejemplo de una vez!

Pues vamos a ello🙂

Bloqueo de peticiones repetidas mediante .data()

Como hemos dicho, vamos a utilizar la técnica del semáforo para comprobar si podemos realizar la petición o no. La idea es muy sencilla: Justo antes de enviar la petición AJAX, pondremos el semáforo a rojo para que ninguna otra petición pueda pasar y una vez que hayamos recibido una respuesta a esa petición, volveremos a poner el semáforo en verde para que la siguiente petición pueda ser enviada. Sencillo, ¿verdad?.

Lo primero que haremos será capturar el evento submit de nuestro formulario y asignarle a este formulario una serie de datos con la función data().

Vamos a verlo en código y veréis que el propio código es autoexplicativo:

$(document).ready(function(){
   $('form#envio-info').submit(function(evt){ //Capturamos el submit
      evt.preventDefault();
       //Guardamos la referencia al formulario
       var $f = $(this);
       //Comprobamos si el semaforo esta en verde (1)
       if ($f.data('locked') != undefined && !$f.data('locked')){
        //No esta bloqueado aun, bloqueamos, preparamos y enviamos la peticion
         $.ajax({
             url: '/urlQueNosInterese',
             data: $f.serialize(), //por ejemplo
             beforeSend: function(){ $f.data('locked', true);  // (2)},
             success: function(){//Lo que nos interese},
             error: function(){//Lo que nos interese},
             complete: function(){ $f.data('locked', false);  // (3)}
         });
      }else{
         //Bloqueado!!!
      }
   });
});

Como veis, antes de configurar la petición AJAX, preguntamos si el formulario tiene asociado datos para la clave ‘locked’ y además comprobamos que esos datos sean ‘false’ (1). Si esta condición se cumple (el semáforo está en verde) empezaremos a preparar la petición AJAX. Antes de enviar la petición lo primero que hacemos (beforeSend) es poner el semáforo a rojo dándole valor a la clave ‘locked’ (2). Por último, una vez que la petición AJAX finaliza (complete) sin importar el resultado, volvemos a poner el semáforo en verde (3).

Como puede apreciarse, el código es muy sencillo y el modo de implementar el semáforo es muy simple, pero nos permite ignorar los clicks que se hagan sobre el submit del formulario si aún no ha terminado de procesarse alguna petición anterior.

Y ya sabéis, cualquier consulta, duda, mejora…. será, como siempre, muy bien recibida.

Más Info:

jQuery | Data Documentation
jQuery | Data API
jQuery | removeData API
jQuery | ajax API

6 comentarios leave one →
  1. Jesus permalink
    4 junio 2012 18:59

    Muchas gracias por este aporte me fue muy util!

  2. 5 septiembre 2012 00:05

    Gracias por el aporte, te corrigo un error en la siguiente parte

    //Comprobamos si el semaforo esta en verde (1)
    if ($f.data(‘locked’) != undefined && !$f.data(‘locked’)){
    //No esta bloqueado aun, bloqueamos, preparamos y enviamos la peticion

    Hay un error en el if, ya que debes preguntar es $f.data(‘locked’) == undefined, por que en caso de no estar bloqueado, puede tratarse de que no este definido o no bloqueado, por lo tanto no puedes preguntar por != sino por == quedando el if de la siguiente manera.

    if ($f.data(‘locked’) == undefined && !$f.data(‘locked’))

    • 5 octubre 2013 10:27

      creo que mas bien la condición debería ser..
      if ($f.data(‘locked’) == undefined || !$f.data(‘locked’))
      si no esta definida o si no esta bloqueada..

      • Camilo Gonzalez permalink
        8 julio 2014 18:55

        Gente, muy bueno el tutorial, yo creo que sólo dejando la condición (!$.data(‘locked’)) es más que suficiente y con eso también puede volver a enviarlo luego de haberlo reseteado por supuesto.

  3. Rafa permalink
    18 septiembre 2012 16:55

    Gracias por tu aportación, me está siendo muy util.

    Aunque tengo una duda:

    ¿Tal y como has desarrollado el algoritmo, nos aseguramos que las operaciones de comprobación y asignación sobre el semáforo sean atómicas?

    Estoy usando la función “setInterval” para hacer cargas asíncronas cada X segundos y me quiero asegurar de no hacer más de una petición al mismo tiempo.

    Muchas gracias de antemano.

  4. josemi permalink
    25 julio 2016 17:08

    gracias por el aporte, estupendo me sirvio

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: