Aquí hay un ejemplo artificial de lo que está sucediendo: http://jsfiddle.net/adamjford/YNGcm/20/
HTML:
<a href="#">Click me!</a>
<div></div>
JavaScript:
function getSomeDeferredStuff() {
var deferreds = [];
var i = 1;
for (i = 1; i <= 10; i++) {
var count = i;
deferreds.push(
$.post('/echo/html/', {
html: "<p>Task #" + count + " complete.",
delay: count
}).success(function(data) {
$("div").append(data);
}));
}
return deferreds;
}
$(function() {
$("a").click(function() {
var deferreds = getSomeDeferredStuff();
$.when(deferreds).done(function() {
$("div").append("<p>All done!</p>");
});
});
});
Quiero "¡Todo listo!" aparecer después de que se hayan completado todas las tareas diferidas, pero $.when()
no parece saber cómo manejar una matriz de objetos diferidos. "¡Todo listo!" está sucediendo primero porque la matriz no es un objeto diferido, por lo que jQuery sigue adelante y supone que se acaba de hacer.
Sé que uno podría pasar los objetos a la función, $.when(deferred1, deferred2, ..., deferredX)
pero no se sabe cuántos objetos diferidos habrá en la ejecución del problema real que estoy tratando de resolver.
javascript
jquery
argument-passing
jquery-deferred
.when
adamjford
fuente
fuente
$.when.apply
en absoluto para obtener el mismo resultado.Respuestas:
Para pasar una matriz de valores a cualquier función que normalmente espera que sean parámetros separados, use
Function.prototype.apply
, por lo que en este caso necesita:Ver http://jsfiddle.net/YNGcm/21/
En ES6, puede utilizar el
...
operador de propagación en su lugar:En cualquier caso, dado que es poco probable que sepa de antemano cuántos parámetros formales
.then
requerirá el controlador, ese controlador necesitará procesar laarguments
matriz para recuperar el resultado de cada promesa.fuente
$.when
:f.apply(ctx, my_array)
llamaráf
conthis == ctx
y los argumentos se ajustarán al contenido demy_array
.$
vsnull
como primer parámetro. Sin embargo, en este caso particular no importa.$
escribe menosnull
y está seguro cuando la$.when
implementación cambia (no es probable que sea en este caso, pero por qué no se mantienethis
sin cambios por defecto).Las soluciones anteriores (gracias!) No abordan adecuadamente el problema de volver a los objetos proporcionados a la del diferida
resolve()
método porque jQuery llamadone()
yfail()
devoluciones de llamada con los parámetros individuales, no una matriz. Eso significa que tenemos que usar laarguments
pseudo-matriz para obtener todos los objetos resueltos / rechazados devueltos por la matriz de diferidos, lo cual es feo:Dado que aprobamos una serie de aplazamientos, sería bueno recuperar una serie de resultados. También sería bueno recuperar una matriz real en lugar de una pseudo-matriz para que podamos usar métodos como
Array.sort()
.Aquí hay una solución inspirada en el método de when.js
when.all()
que aborda estos problemas:Ahora puede simplemente pasar una matriz de diferidos / promesas y recuperar una matriz de objetos resueltos / rechazados en su devolución de llamada, de esta manera:
fuente
var toArray = function (args) { return deferreds.length > 1 ? $.makeArray(args) : [args]; }
lugar deArray.prototype.slice.call
.Puede aplicar el
when
método a su matriz:¿Cómo trabaja con una variedad de jQuery Deferreds?
fuente
Al llamar a varias llamadas AJAX paralelas, tiene dos opciones para manejar las respuestas respectivas.
Promises'
array y$.when
que aceptepromise
s y su devolución de llamada.done
se llama cuando todos lospromise
s se devuelven correctamente con las respuestas respectivas.Ejemplo
fuente
$.when
.for ... in
en una matriz ?!)(not recommended)
2. No está de acuerdo -for ... in
está bien porque la matriz contiene solo aquellas propiedades que necesitan (sin propiedades adicionales). gracias de todos modosArray.prototype
. En cualquier caso, para un código que no sea crítico para el rendimiento, sería mejor usarlo en.map
lugar de un buclefor
/push
, por ejemplovar promises = capitalCities.map(ajaxRequest); $.when.apply($, promises).then(fillCountryCapitals)
, trabajo realizado.Como alternativa simple, que no requiere
$.when.apply
o unaarray
, puede usar el siguiente patrón para generar una sola promesa para múltiples promesas paralelas:p.ej
Notas:
promise = promise.then(newpromise)
fuente
then()
llamadas de manera similar. El comportamiento con$.when
es actuar como si fuera paralelo (no encadenado). Por favor, pruébalo antes de tirar una alternativa útil, ya que funciona :)Quiero proponer otro usando $ .each:
Podemos declarar la función ajax como:
Parte del código donde creamos una matriz de funciones con ajax para enviar:
Y llamando a funciones con el envío de ajax:
fuente
Si está transpilando y tiene acceso a ES6, puede usar la sintaxis extendida que aplica específicamente cada elemento iterable de un objeto como un argumento discreto, tal como lo
$.when()
necesita.MDN Link - Sintaxis extendida
fuente
Si está utilizando angularJS o alguna variante de la biblioteca de promesa Q, entonces tiene un
.all()
método que resuelve este problema exacto.ver la API completa:
https://github.com/kriskowal/q/wiki/API-Reference#promiseall
https://docs.angularjs.org/api/ng/service/$q
fuente
.map
aquí, pero bueno).Tuve un caso muy similar en el que publicaba en cada bucle y luego configuraba el marcado html en algunos campos de los números recibidos del ajax. Luego necesitaba hacer una suma de los valores (ahora actualizados) de estos campos y colocarlos en un campo total.
Por lo tanto, el problema era que estaba tratando de hacer una suma de todos los números, pero aún no había recibido datos de las llamadas asíncronas ajax. Necesitaba completar esta funcionalidad en algunas funciones para poder reutilizar el código. Mi función externa espera los datos antes de ir y hacer algunas cosas con el DOM completamente actualizado.
fuente