Odio las funciones callback en las llamadas ajax. Pese a que me encantan las funciones anónimas, pierdo el control muy fácilmente cuando encadeno una llamada ajax detrás de otra.

Revisando la documentación de la función ajax de jQuery, he dado con la solución al problema.

Resulta que desde la versión 1.5 de jQuery, cada llamada a la función $.ajax devuelve un deferred object, que implementa la interfa Promise. Entre otras cosas, nos permiten determinar la función done(), especificando el callback a invocar a continuación de la declaración de la llamada. La función done se ejecutaría cuando la llamada ajax se ha realizado correctamente (reemplazando así al success de $.ajax), mientras que la función fail() se ejecutaría en caso de error (sustituyendo al error de $.ajax). El siguiente fiddle muestra ese ejemplo.

var firstCall = function(){
    //Llamada ajax: realiza una consulta para obtener el nombre y URL del sitio web
    var firstAjaxCall = $.ajax({
        url: '/echo/json/',
        type: 'POST',
        data: {
            json: JSON.stringify({name: 'veamospues', url: 'http://www.veamospues.wordpress.com'}),
            delay: 3 
        }
    });
    
    //Acción a realizar cuando hayamos terminado la llamada ajax
    firstAjaxCall.done(function(data){
        alert(data.name + " ("+data.url+")");
    });
};

Bueno, con esto parece que no ganemos mucho, pero al menos ya nos permite organizar nuestro código de con un aspecto más secuencial.

Otra cosa que nos permite un deferred object es el encadenamiento de funciones. Así, podemos organizarnos mejor y definir, secuencialmente, el conjunto de acciones a llevar a cabo una vez ha finalizado una llamada ajax. Así, no es necesario definir un callback que haga una llamada a cada una de las funcionalidades independientes.

var secondCall = function(){
    //Llamada ajax: realiza una consulta para obtener el nombre y URL del sitio web
    var secondAjaxCall = $.ajax({
        url: '/echo/json/',
        type: 'POST',
        data: {
            json: JSON.stringify({name: 'veamospues', url: 'http://www.veamospues.wordpress.com'}),
            delay: 3 
        }
    });
    
    secondAjaxCall.done(function(data){
        //Primer callback: mostrar nombre
        alert(data.name);
    });
    
    secondAjaxCall.done(function(data){
        //Segunda callback: mostrar url
        alert(data.url);
    });
};

Podemos ver este ejemplo funcionando en este otro fiddle.

Por último, y quizá éste sea el caso más interesante, los deferred objects nos permiten lanzar un callback cuando hemos completado más de una llamada ajax. Digo llamada ajax porque es en lo que nos estamos centrando aquí, pero sabiendo que son implementaciones de interfaces, sabemos que no tiene por qué ser necesariamente así. A lo que iba, podemos definir una función de callback que se ejecute, exclusivamente, cuando han finalizado todas las llamadas. El último fiddle ilustra este ejemplo:

var thirdCall = function(){
    //Primera llamada ajax: realiza una consulta para obtener el nombre del sitio web
    var thirdAjaxCall = $.ajax({
        url: '/echo/json/',
        type: 'POST',
        data: {
            json: JSON.stringify({name: 'veamospues'}),
            delay: 1 
        }
    });

    //Segunda llamada ajax: realiza una consulta para obtener la URL del sitio web    
    var fourthAjaxCall = $.ajax({
        url: '/echo/json/',
        type: 'POST',
        data: {
            json: JSON.stringify({url: 'http://www.veamospues.wordpress.com'}),
            delay: 2
        }
    });
    
    //Cuando hayamos completado las dos llamadas, mostramos el nombre y la URL
    $.when(thirdAjaxCall, fourthAjaxCall).done(function(dataName, dataUrl){
        alert(dataName[0].name + " ("+dataUrl[0].url+")");
    });
    
};

$(document).ready(function(){
    $('#third-call').click(thirdCall);
});

Cada parámetro se corresponderá con un array, ya que la función done, cuando se trata de llamadas ajax, espera tres argumentos: data, textStatus, jqXHR.

Espero que al igual que yo, esto os sirva para conocer algo más que no conocíais acerca de jQuery. Deciros que, además, desde la versión 1.5 de jQuery se recomienda el uso de estas funciones, dándose por deprecated las propias de las llamadas ajax.

Anuncios