done jquery ajax arrays promise jquery-deferred

done - jQuery, $.ajax con una matriz de URL



jquery ajax promise (2)

Tengo una matriz simple de URL, y quiero cargar cada una con jQuery. Estaba usando $.get , pero parece que no puedo hacer que funcione con $.Deferred , así que $.Deferred a $.ajax - Casi lo tengo funcionando, pero los resultados que obtengo son ... extraños. Esperaba que alguien pudiera ayudarme a hacer que esto funcionara mejor.

var results = [], files = [ ''url1'', ''url2'', ''url3'' ]; $.when( $.ajax(files[0]).done(function(data) { results.push(data); console.log("step 1.0"); }), $.ajax(files[1]).done(function(data) { results.push(data); console.log("step 1.1"); }), $.ajax(files[2]).done(function(data) { results.push(data); console.log("step 1.2"); }) ).then(function(){ console.log("step 2"); });

Esto debería generar ...

  • paso 1.0
  • paso 1.1
  • paso 1.2
  • paso 2

Y luego la matriz de results contiene el resultado de las 3 solicitudes ajax. es posible?


Debería acceder a los valores de retorno desde .then en lugar de cada .done. Además, .map es tu amigo.

var results = [], files = [ ''url1'', ''url2'', ''url3'' ]; $.when.apply($, $.map(files, function (file) { return $.ajax(file); })).then(function (dataArr) { /* * dataArr is an array of arrays, * each array contains the arguments * returned to each success callback */ results = $.map(dataArr, function (data) { return data[0]; // the first argument to the success callback is the data }); console.log(results); });

los argumentos pasados ​​a .then estarán en el mismo orden en que se pasaron a .when


En primer lugar, debe decidir si desea que sus tres llamadas ajax se procesen en paralelo (ejecutando todas al mismo tiempo, con menos tiempo de ejecución general) o en secuencia donde ejecuta una llamada ajax, finaliza y luego lanza la siguiente ajax llamada. Esta es una decisión clave de diseño que impacta en cómo lo hace.

Cuando usa $.when() está lanzando las tres llamadas ajax en paralelo. Si examina los resultados solo cuando todos se hayan completado, aún puede procesar los resultados en un orden específico (ya que los procesará solo cuando todos los resultados estén disponibles y estarán disponibles en el orden solicitado). Pero, al hacerlo de esta manera, todas las llamadas ajax se enviarán inicialmente a la vez. Esto le proporcionará un mejor tiempo de extremo a extremo, de modo que si esto es factible para los tipos de solicitudes, esta es, por lo general, una mejor manera de hacerlo.

Para hacer eso, puedes reestructurar lo que tienes para algo como esto:

Ejecutar en Paralelo

var files = [ ''url1'', ''url2'', ''url3'' ]; $.when($.ajax(files[0]),$.ajax(files[1]),$.ajax(files[2])).done(function(a1, a2, a3) { var results = []; results.push(a1[0]); results.push(a2[0]); results.push(a3[0]); console.log("got all results") });

Como está esperando hasta que se haya llamado al controlador .done() para $.when() , todos los resultados de ajax están listos a la vez y se presentan por $.when() en el orden en que fueron solicitados (independientemente de cuál uno realmente terminó primero), por lo que obtienes los resultados lo más rápido posible y se presentan en un orden predecible.

Tenga en cuenta que también moví la definición de la matriz de results al manejador $.when() done porque ese es el único lugar donde sabe que los datos son realmente válidos (por razones de tiempo).

Ejecutar en paralelo: iterar matriz de longitud arbitraria

Si tiene una matriz más larga, puede encontrar que es mejor iterar a través de la matriz con algo como .map() para procesarlos todos en un bucle en lugar de enumerarlos individualmente:

var files = [ ''url1'', ''url2'', ''url3'', ''url4'', ''url5'', ''url6'', ''url7'' ]; $.when.apply($, files.map(function(url) { return $.ajax(url); })).done(function() { var results = []; // there will be one argument passed to this callback for each ajax call // each argument is of this form [data, statusText, jqXHR] for (var i = 0; i < arguments.length; i++) { results.push(arguments[i][0]); } // all data is now in the results array in order });

Secuencia de las llamadas Ajax

Si, por otro lado, realmente quieres secuenciar tus llamadas ajax para que el segundo no comience hasta que termine el primero (algo que pueda ser necesario si la segunda llamada ajax necesita resultados de la primera llamada ajax para saber qué pedir o hacer), entonces necesita un patrón de diseño completamente diferente y $.when() no es el camino a seguir en absoluto (solo hace solicitudes paralelas). En ese caso, probablemente solo quiera encadenar los resultados con x.then().then() y luego podrá dar salida a las instrucciones de registro en la secuencia que solicitó de esta manera.

$.ajax(files[0]).then(function(data0) { console.log("step 1.0"); return $.ajax(files[1]); }).then(function(data1) { console.log("step 1.1"); return $.ajax(files[2]); }).done(function(data2) { console.log("step 1.2"); // all the ajax calls are done here console.log("step 2"); });

Salida de consola:

step 1.0 step 1.1 step 1.2 step 2

Esta estructura también se puede poner en un bucle para ejecutarla automáticamente para N llamadas ajax secuenciales si su matriz de archivos es más larga. Si bien puede recopilar los resultados a medida que avanza en la matriz de results , a menudo la razón por la que se realizan las cosas de forma secuencial es que los resultados anteriores se consumen en la próxima llamada ajax, por lo que a menudo solo necesita el resultado final. Si desea recopilar los resultados sobre la marcha, sin duda podría insertarlos en la matriz de results en cada paso.

Tenga en cuenta que las ventajas que ofrecen las promesas aquí son que puede secuenciar las operaciones mientras permanece en el mismo nivel superior de anidación y no anida más.

Secuencia de las llamadas Ajax - Iterar Arbitrary Length Array

Así es como se vería la secuencia en un ciclo:

var files = [ ''url1'', ''url2'', ''url3'', ''url4'', ''url5'', ''url6'', ''url7'' ]; var results = []; files.reduce(function(prev, cur, index) { return prev.then(function(data) { return $.ajax(cur).then(function(data) { console.log("step 1." + index); results.push(data); }); }) }, $().promise()).done(function() { // last ajax call done // all results are in the results array console.log("step 2.0"); });

Salida de consola:

step 1.0 step 1.1 step 1.2 step 1.3 step 1.4 step 1.5 step 1.6 step 2

El método Array.prototype.reduce() funciona muy bien aquí porque acumula un único valor a medida que procesa cada elemento de matriz individual, que es lo que debe hacer cuando agrega .then() para cada elemento de la matriz. La iteración .reduce() se inicia con una promesa vacía / resuelta con $().promise() (hay otras formas de crear también una promesa) que simplemente nos da algo para empezar a hacer .then() en eso ya está resuelto.