devolución de llamada jQuery para múltiples llamadas ajax

Resuelto MisterIsaak asked hace 14 años • 14 respuestas

Quiero hacer tres llamadas ajax en un evento de clic. Cada llamada ajax realiza una operación distinta y devuelve los datos necesarios para una devolución de llamada final. Las llamadas en sí no dependen una de otra, todas pueden realizarse al mismo tiempo, sin embargo, me gustaría tener una devolución de llamada final cuando las tres estén completas.

$('#button').click(function() {
    fun1();
    fun2();
    fun3();
//now do something else when the requests have done their 'success' callbacks.
});

var fun1= (function() {
    $.ajax({/*code*/});
});
var fun2 = (function() {
    $.ajax({/*code*/});
});
var fun3 = (function() {
    $.ajax({/*code*/});
});
MisterIsaak avatar Dec 07 '10 00:12 MisterIsaak
Aceptado

Parece que tienes algunas respuestas a esto, sin embargo, creo que hay algo que vale la pena mencionar aquí y que simplificará enormemente tu código. jQuery introdujo el $.whenen v1.5. Parece que:

$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
    //this callback will be fired once all ajax calls have finished.
});

No lo vi mencionado aquí.

Greg avatar Nov 20 '2011 08:11 Greg

Aquí hay un objeto de devolución de llamada que escribí donde puedes configurar una única devolución de llamada para que se active una vez que se haya completado o dejar que cada uno tenga su propia devolución de llamada y que se activen todas una vez que se hayan completado:

AVISO

Desde jQuery 1.5+ puedes usar el método diferido como se describe en otra respuesta:

  $.when($.ajax(), [...]).then(function(results){},[...]);

Ejemplo de diferido aquí

para jQuery < 1.5 lo siguiente funcionará o si necesita que sus llamadas ajax se activen en momentos desconocidos como se muestra aquí con dos botones: se activan después de hacer clic en ambos botones

[uso]

para devolución de llamada única una vez completada: Ejemplo de trabajo

// initialize here
var requestCallback = new MyRequestsCompleted({
    numRequest: 3,
    singleCallback: function(){
        alert( "I'm the callback");
    }
});

//usage in request
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});

cada uno tiene su propia devolución de llamada cuando todo está completo: Ejemplo de trabajo

//initialize 
var requestCallback = new MyRequestsCompleted({
    numRequest: 3
});

//usage in request
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the first callback');
        });
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the second callback');
        });
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the third callback');
        });
    }
});

[El código]

var MyRequestsCompleted = (function() {
    var numRequestToComplete, requestsCompleted, callBacks, singleCallBack;

    return function(options) {
        if (!options) options = {};

        numRequestToComplete = options.numRequest || 0;
        requestsCompleted = options.requestsCompleted || 0;
        callBacks = [];
        var fireCallbacks = function() {
            alert("we're all complete");
            for (var i = 0; i < callBacks.length; i++) callBacks[i]();
        };
        if (options.singleCallback) callBacks.push(options.singleCallback);

        this.addCallbackToQueue = function(isComplete, callback) {
            if (isComplete) requestsCompleted++;
            if (callback) callBacks.push(callback);
            if (requestsCompleted == numRequestToComplete) fireCallbacks();
        };
        this.requestComplete = function(isComplete) {
            if (isComplete) requestsCompleted++;
            if (requestsCompleted == numRequestToComplete) fireCallbacks();
        };
        this.setCallback = function(callback) {
            callBacks.push(callBack);
        };
    };
})();
subhaze avatar Dec 06 '2010 18:12 subhaze

No veo la necesidad de ningún objeto. Simple tiene una variable que es un número entero. Cuando inicie una solicitud, incremente el número. Cuando uno se complete, disminuya. Cuando es cero, no hay solicitudes en curso, así que ya está.

$('#button').click(function() {
    var inProgress = 0;

    function handleBefore() {
        inProgress++;
    };

    function handleComplete() {
        if (!--inProgress) {
            // do what's in here when all requests have completed.
        }
    };

    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
});
Matt avatar Dec 06 '2010 18:12 Matt

Vale la pena señalar que, dado que $.whenespera que todas las solicitudes ajax sean argumentos secuenciales (no una matriz), comúnmente verá que $.whense usan .apply()así:

// Save all requests in an array of jqXHR objects
var requests = arrayOfThings.map(function(thing) {
    return $.ajax({
        method: 'GET',
        url: 'thing/' + thing.id
    });
});

$.when.apply(this, requests).then(function(resp1, resp2/*, ... */) {
    // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
    var responseArgsArray = Array.prototype.slice.call(this, arguments);

});

Usando la sintaxis Spread , ahora puedes escribir este código así:

$.when(...requests).then((...responses) => {
    // do something with responses
})

Esto se debe a que $.whenacepta argumentos como este.

$.when(ajaxRequest1, ajaxRequest2, ajaxRequest3);

Y no así:

$.when([ajaxRequest1, ajaxRequest2, ajaxRequest3]);
Cory Danielson avatar Jun 02 '2016 04:06 Cory Danielson