javascript - example - Espera hasta que todas las solicitudes de jQuery Ajax estén listas?
enviar json por post jquery (20)
¿Cómo hago que una función espere hasta que todas las solicitudes de jQuery Ajax se realicen dentro de otra función?
En resumen, debo esperar a que se realicen todas las solicitudes de Ajax antes de ejecutar la siguiente. ¿Pero cómo?
Encontré este problema y creé un complemento genérico jquery_counter para resolverlo: https://bitbucket.org/stxnext/jquery_counter/
Encontré una buena respuesta por parte de gnarf que es exactamente lo que estaba buscando :)
jQuery ajaxQueue
//This handles the queues
(function($) {
var ajaxQueue = $({});
$.ajaxQueue = function(ajaxOpts) {
var oldComplete = ajaxOpts.complete;
ajaxQueue.queue(function(next) {
ajaxOpts.complete = function() {
if (oldComplete) oldComplete.apply(this, arguments);
next();
};
$.ajax(ajaxOpts);
});
};
})(jQuery);
Luego puede agregar una solicitud ajax a la cola como esta:
$.ajaxQueue({
url: ''page.php'',
data: {id: 1},
type: ''POST'',
success: function(data) {
$(''#status'').html(data);
}
});
Estoy usando la verificación de tamaño cuando toda la carga de ajax se complete
//multiple ajax calls above
var callback = function () {
if ($.active !== 0) {
setTimeout(callback, ''500'');
return;
}
//whatever you need to do here
//...
};
callback();
function waitReq(id)
{
jQuery.ajax(
{
type: ''POST'',
url: ajaxurl,
data:
{
"page": id
},
success: function(resp)
{
...........
// check array length if not "0" continue to use next array value
if(ids.length)
{
waitReq(ids.shift()); // 2
)
},
error: function(resp)
{
....................
if(ids.length)
{
waitReq(ids.shift());
)
}
});
}
var ids = [1, 2, 3, 4, 5];
// shift() = delete first array value (then print)
waitReq(ids.shift()); // print 1
La solución dada por Alex funciona bien. El mismo concepto, pero usándolo de una manera un poco diferente (cuando no se conoce de antemano el número de llamadas)
http://garbageoverflow.blogspot.com/2014/02/wait-for-n-or-multiple-or-unknown.html
Lo encontré de manera simple, usando shift()
var runFunctionQueue_callback;
function runFunctionQueue(f, index, callback) {
var next_index = index + 1
if (callback !== undefined) runFunctionQueue_callback = callback;
if (f[next_index] !== undefined) {
console.log(index + '' Next function avalaible -> '' + next_index);
$.ajax({
type: ''GET'',
url: f[index].file,
data: (f[index].data),
complete: function() {
runFunctionQueue(f, next_index);
}
});
} else {
console.log(index + '' Last function'');
$.ajax({
type: ''GET'',
url: f[index].file,
data: (f[index].data),
async: false,
complete: runFunctionQueue_callback
});
}
}
Mi solución es la siguiente
var f = [
{file: ''file_path'', data: {action: ''action'', data: ''any_data}},
{file: ''file_path'', data: {action: ''action'', data: ''any_data}},
{file: ''file_path'', data: {action: ''action'', data: ''any_data}},
{file: ''file_path'', data: {action: ''action'', data: ''any_data}}
];
Funcionó bastante bien. He probado muchas formas diferentes de hacer esto, pero encontré que esta es la más simple y reutilizable. Espero eso ayude
Mira mi solución:
1.Introduzca esta función (y variable) en su archivo javascript:
function Function_callback() {
alert(''done'');
}
2.Builice una matriz con sus solicitudes, como esta:
runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function
3.Crear función de devolución de llamada:
function get_ajax(link, data, callback) {
$.ajax({
url: link,
type: "GET",
data: data,
dataType: "json",
success: function (data, status, jqXHR) {
callback(jqXHR.status, data)
},
error: function (jqXHR, status, err) {
callback(jqXHR.status, jqXHR);
},
complete: function (jqXHR, status) {
}
})
}
function run_list_ajax(callback){
var size=0;
var max= 10;
for (let index = 0; index < max; index++) {
var link = ''http://api.jquery.com/ajaxStop/'';
var data={i:index}
get_ajax(link,data,function(status, data){
console.log(index)
if(size>max-2){
callback(''done'')
}
size++
})
}
}
run_list_ajax(function(info){
console.log(info)
})
4. Llame a la función runFunctionQueue con los parámetros:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
Prueba de esta manera Haga un bucle dentro de la función de script java para esperar hasta que finalice la llamada ajax.
function getLabelById(id)
{
var label = '''';
var done = false;
$.ajax({
cache: false,
url: "YourMvcActionUrl",
type: "GET",
dataType: "json",
async: false,
error: function (result) {
label=''undefined'';
done = true;
},
success: function (result) {
label = result.Message;
done = true;
}
});
//A loop to check done if ajax call is done.
while (!done)
{
setTimeout(function(){ },500); // take a sleep.
}
return label;
}
Recomiendo usar $.when() si estás empezando desde cero.
A pesar de que esta pregunta tiene más de un millón de respuestas, todavía no encontré nada útil para mi caso. Digamos que tiene que lidiar con una base de código existente, ya está haciendo algunas llamadas ajax y no quiere introducir la complejidad de las promesas y / o rehacer todo.
Podemos aprovechar fácilmente las funciones de jQuery .data
, .on
y .trigger
que han sido parte de jQuery desde siempre.
Lo bueno de mi solución es:
Es obvio de qué depende exactamente la devolución de llamada
a la función
triggerNowOrOnLoaded
no le importa si los datos ya se han cargado o todavía lo estamos esperandoEs muy fácil conectarlo a un código existente
$(function() {
// wait for posts to be loaded
triggerNowOrOnLoaded("posts", function() {
var $body = $("body");
var posts = $body.data("posts");
$body.append("<div>Posts: " + posts.length + "</div>");
});
// some ajax requests
$.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
$("body").data("posts", data).trigger("posts");
});
// doesn''t matter if the `triggerNowOrOnLoaded` is called after or before the actual requests
$.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
$("body").data("users", data).trigger("users");
});
// wait for both types
triggerNowOrOnLoaded(["posts", "users"], function() {
var $body = $("body");
var posts = $body.data("posts");
var users = $body.data("users");
$body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
});
// works even if everything has already loaded!
setTimeout(function() {
// triggers immediately since users have been already loaded
triggerNowOrOnLoaded("users", function() {
var $body = $("body");
var users = $body.data("users");
$body.append("<div>Delayed Users: " + users.length + "</div>");
});
}, 2000); // 2 seconds
});
// helper function
function triggerNowOrOnLoaded(types, callback) {
types = $.isArray(types) ? types : [types];
var $body = $("body");
var waitForTypes = [];
$.each(types, function(i, type) {
if (typeof $body.data(type) === ''undefined'') {
waitForTypes.push(type);
}
});
var isDataReady = waitForTypes.length === 0;
if (isDataReady) {
callback();
return;
}
// wait for the last type and run this function again for the rest of the types
var waitFor = waitForTypes.pop();
$body.on(waitFor, function() {
// remove event handler - we only want the stuff triggered once
$body.off(waitFor);
triggerNowOrOnLoaded(waitForTypes, callback);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>Hi!</body>
Si desea esperar hasta que todas las solicitudes de ajax hayan finalizado en su documento, sin importar cuántas de ellas existan, simplemente use el evento $.ajaxStop
esta manera:
$(document).ajaxStop(function () {
// 0 === $.active
});
En este caso, no es necesario adivinar cuántas solicitudes puede haber en una aplicación que pueda finalizar en el futuro. En algunos casos, las solicitudes de ajax pueden ser parte de la lógica interna de una función, que puede ser bastante complicada (por ejemplo, llamar a otras funciones), y en ese caso, es posible que no espere hasta que dicha función termine con toda su lógica en lugar de solo esperar a ajax
parte para completar.
$.ajaxStop
aquí también puede vincularse a cualquier nodo HTML
que crea que pueda ser modificado por ajax
.
Nuevamente, el propósito de este controlador es saber cuando no hay un ajax
activo para no borrar o restablecer algo.
PS Si no le importa usar la sintaxis de ES6, entonces puede usar Promise.all
para los métodos conocidos de ajax
. Ejemplo:
Promise.all([ajax1(), ajax2()]).then(() => {
// all requests finished successfully
}).catch(() => {
// all requests finished but one or more failed
})
Un punto interesante aquí es que funciona tanto con las Promises
como con las solicitudes de $.ajax
. Aquí está jsFiddle demostrando el último.
Si necesitas algo simple; una vez y hecho callback
var request;
...
''services'': {
''GetAddressBookData'': function() {
//This is the primary service that loads all addressbook records
request = $.ajax({
type: "POST",
url: "Default.aspx/GetAddressBook",
contentType: "application/json;",
dataType: "json"
});
},
...
''apps'': {
''AddressBook'': {
''data'': "",
''Start'': function() {
...services.GetAddressBookData();
request.done(function(response) {
trace("ajax successful");
..apps.AddressBook.data = response[''d''];
...apps.AddressBook.Filter();
});
request.fail(function(xhr, textStatus, errorThrown) {
trace("ajax failed - " + errorThrown);
});
Sobre la base de la respuesta de @BBonifield, escribí una función de utilidad para que la lógica del semáforo no se propague en todas las llamadas ajax.
untilAjax
es la función de utilidad que invoca una función de devolución de llamada cuando se completan todas las ajaxCalls.
ajaxObjs
es una matriz de objetos de configuración ajax [http://api.jquery.com/jQuery.ajax/]
.
fn
es la función de devolución de llamada
function untilAjax(ajaxObjs, fn) {
if (!ajaxObjs || !fn) {
return;
}
var ajaxCount = ajaxObjs.length,
succ = null;
for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
succ = ajaxObjs[i][''success''];
ajaxObjs[i][''success''] = function(data) { //modified success handler
if (succ) {
succ(data);
}
ajaxCount--;
if (ajaxCount == 0) {
fn(); //modify statement suitably if you want ''this'' keyword to refer to another object
}
};
$.ajax(ajaxObjs[i]); //make ajax call
succ = null;
};
Ejemplo: la función untilAjax
usa untilAjax
.
function doSomething() {
// variable declarations
untilAjax([{
url: ''url2'',
dataType: ''json'',
success: function(data) {
//do something with success data
}
}, {
url: ''url1'',
dataType: ''json'',
success: function(data) {
//do something with success data
}
}, {
url: ''url2'',
dataType: ''json'',
success: function(response) {
//do something with success data
}
}], function() {
// logic after all the calls are completed.
});
}
También puedes usar async.js .
Creo que es mejor que $ .cuando se puede combinar todo tipo de llamadas asíncronas que no admiten promesas de fábrica, como tiempos de espera, llamadas SqlLite, etc. y no solo solicitudes ajax.
Una pequeña solución es algo como esto:
// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
counter++;
if( counter >= ajaxCalls ) {
// When all ajax calls has been done
// Do something like hide waiting images, or any else function call
$(''*'').css(''cursor'', ''auto'');
}
};
var loadPersons = function() {
// Show waiting image, or something else
$(''*'').css(''cursor'', ''wait'');
var url = global.ctx + ''/loadPersons'';
$.getJSON(url, function(data) {
// Fun things
})
.complete(function() { **ajaxCallComplete();** });
};
var loadCountries = function() {
// Do things
var url = global.ctx + ''/loadCountries'';
$.getJSON(url, function(data) {
// Travels
})
.complete(function() { **ajaxCallComplete();** });
};
var loadCities = function() {
// Do things
var url = global.ctx + ''/loadCities'';
$.getJSON(url, function(data) {
// Travels
})
.complete(function() { **ajaxCallComplete();** });
};
$(document).ready(function(){
loadPersons();
loadCountries();
loadCities();
});
La esperanza puede ser útil ...
Utiliza el evento ajaxStop
.
Por ejemplo, supongamos que tiene un mensaje de carga ... al recuperar 100 solicitudes ajax y desea ocultar ese mensaje una vez cargado.
Desde el $.ajaxStop jQuery:
$("#loading").ajaxStop(function() {
$(this).hide();
});
Tenga en cuenta que esperará a que todas las solicitudes de ajax se realicen en esa página.
jQuery ahora define una función when para este propósito.
Acepta cualquier número de objetos diferidos como argumentos y ejecuta una función cuando todos se resuelven.
Eso significa que, si desea iniciar (por ejemplo) cuatro solicitudes ajax, luego realizar una acción cuando se realicen, podría hacer algo como esto:
$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
// the code here will be executed when all four ajax requests resolve.
// a1, a2, a3 and a4 are lists of length 3 containing the response text,
// status, and jqXHR object for each of the four ajax calls respectively.
});
function ajax1() {
// NOTE: This function must return the value
// from calling the $.ajax() method.
return $.ajax({
url: "someUrl",
dataType: "json",
data: yourJsonData,
...
});
}
En mi opinión, crea una sintaxis limpia y clara, y evita involucrar a variables globales como ajaxStart y ajaxStop, que podrían tener efectos secundarios no deseados a medida que se desarrolla su página.
Si no sabe de antemano cuántos argumentos ajax necesita esperar (es decir, si desea utilizar un número variable de argumentos), aún puede hacerse, pero es un poco más complicado. Consulte Pasar en una matriz de diferidos a $ .when () (y tal vez jQuery .when solución de problemas con un número variable de argumentos ).
Si necesita un control más profundo sobre los modos de falla de los scripts ajax, etc., puede guardar el objeto devuelto por .when()
- es un objeto jQuery Promise que abarca todas las consultas originales ajax. Puede llamar a .then()
o .fail()
para agregar controladores detallados de éxito / falla.
jQuery le permite especificar si desea que la solicitud ajax sea asíncrona o no. Simplemente puede hacer que las solicitudes de ajax sean sincrónicas y luego el resto del código no se ejecutará hasta que regresen.
Por ejemplo:
jQuery.ajax({
async: false,
//code
});
javascript está basado en eventos, por lo que nunca debe esperar , en lugar de establecer enlaces / devoluciones de llamada
Probablemente solo puedas usar los métodos exitosos / completos de jquery.ajax
O podrías usar .ajaxComplete :
$(''.log'').ajaxComplete(function(e, xhr, settings) {
if (settings.url == ''ajax/test.html'') {
$(this).text(''Triggered ajaxComplete handler.'');
//and you can do whatever other processing here, including calling another function...
}
});
aunque usted debería publicar un pseudocódigo de cómo se llaman (son) sus solicitudes ajax para ser más precisos ...
$.when
no funciona para mí, la callback(x)
lugar de la return x
funcionó como se describe aquí: https://.com/a/13455253/10357604
NOTA: Las respuestas anteriores utilizan una funcionalidad que no existía en el momento en que se escribió esta respuesta. Recomiendo usar jQuery.when()
lugar de estos enfoques, pero estoy dejando la respuesta para propósitos históricos.
-
Probablemente podría arreglárselas con un simple semáforo de conteo, aunque su implementación dependerá de su código. Un ejemplo simple sería algo como ...
var semaphore = 0, // counting semaphore for ajax requests
all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts
semaphore++;
$.get(''ajax/test1.html'', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get(''ajax/test2.html'', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get(''ajax/test3.html'', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get(''ajax/test4.html'', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;
Si quisiera que esto funcionara como {async: false} pero no quería bloquear el navegador, podría lograr lo mismo con una cola jQuery.
var $queue = $("<div/>");
$queue.queue(function(){
$.get(''ajax/test1.html'', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get(''ajax/test2.html'', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get(''ajax/test3.html'', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get(''ajax/test4.html'', function(data) {
$queue.dequeue();
});
});