when until then finished done completed another after javascript jquery asynchronous promise

javascript - until - ¿Qué hace $.when.apply($, someArray)?



promise ajax jquery (6)

Estoy leyendo sobre Deferreds and Promises y sigo encontrando $.when.apply($, someArray) . No estoy del todo claro sobre qué hace exactamente esto, buscando una explicación de que una línea funciona exactamente (no el fragmento de código completo). Aquí hay un contexto:

var data = [1,2,3,4]; // the ids coming back from serviceA var processItemsDeferred = []; for(var i = 0; i < data.length; i++){ processItemsDeferred.push(processItem(data[i])); } $.when.apply($, processItemsDeferred).then(everythingDone); function processItem(data) { var dfd = $.Deferred(); console.log(''called processItem''); //in the real world, this would probably make an AJAX call. setTimeout(function() { dfd.resolve() }, 2000); return dfd.promise(); } function everythingDone(){ console.log(''processed all items''); }


$. cuando solo hace posible que se llame a una devolución de llamada cuando se resuelven / rechazan todas las promesas que se le pasaron. Normalmente, $ .when toma una cantidad variable de argumentos, el uso de .apply hace posible pasarle una matriz de argumentos, es muy poderoso. Para obtener más información sobre .aplicación: developer.mozilla.org/en-US/docs/JavaScript/Reference/…


Aquí, el código completamente documentado.

// 1. Declare an array of 4 elements var data = [1,2,3,4]; // the ids coming back from serviceA // 2. Declare an array of Deferred objects var processItemsDeferred = []; // 3. For each element of data, create a Deferred push push it to the array for(var i = 0; i < data.length; i++){ processItemsDeferred.push(processItem(data[i])); } // 4. WHEN ALL Deferred objects in the array are resolved THEN call the function // Note : same as $.when(processItemsDeferred[0], processItemsDeferred[1], ...).then(everythingDone); $.when.apply($, processItemsDeferred).then(everythingDone); // 3.1. Function called by the loop to create a Deferred object (data is numeric) function processItem(data) { // 3.1.1. Create the Deferred object and output some debug var dfd = $.Deferred(); console.log(''called processItem''); // 3.1.2. After some timeout, resolve the current Deferred //in the real world, this would probably make an AJAX call. setTimeout(function() { dfd.resolve() }, 2000); // 3.1.3. Return that Deferred (to be inserted into the array) return dfd.promise(); } // 4.1. Function called when all deferred are resolved function everythingDone(){ // 4.1.1. Do some debug trace console.log(''processed all items''); }


Desafortunadamente no puedo estar de acuerdo con ustedes.

$.when.apply($, processItemsDeferred).always(everythingDone);

Llamará a everythingDone en cuanto se rechace un diferido, incluso si hay otros diferidos pendientes .

Aquí está el guión completo (Recomiendo http://jsfiddle.net/ ):

var data = [1,2,3,4]; // the ids coming back from serviceA var processItemsDeferred = []; for(var i = 0; i < data.length; i++){ processItemsDeferred.push(processItem(data[i])); } processItemsDeferred.push($.Deferred().reject()); //processItemsDeferred.push($.Deferred().resolve()); $.when.apply($, processItemsDeferred).always(everythingDone); function processItem(data) { var dfd = $.Deferred(); console.log(''called processItem''); //in the real world, this would probably make an AJAX call. setTimeout(function() { dfd.resolve(); }, 2000); return dfd.promise(); } function everythingDone(){ alert(''processed all items''); }

Es esto un error? Me gustaría usar esto como el caballero arriba descrito.


Gracias por su elegante solución:

var promise; for(var i = 0; i < data.length; i++){ promise = $.when(promise, processItem(data[i])); } promise.then(everythingDone);

Solo un punto: cuando se usa resolveWith para obtener algunos parámetros, se rompe debido a la promesa inicial establecida en undefined. Lo que hice para que funcione

// Start with an empty resolved promise - undefined does the same thing! var promise; for(var i = 0; i < data.length; i++){ if(i==0) promise = processItem(data[i]); else promise = $.when(promise, processItem(data[i])); } promise.then(everythingDone);


$.when toma cualquier número de parámetros y se resuelve cuando todos estos se hayan resuelto.

anyFunction .apply (thisValue, arrayParameters) llama a la función anyFunction configurando su contexto (thisValue será el this dentro de esa llamada de función) y pasa todos los objetos en arrayParameters como parámetros individuales.

Por ejemplo:

$.when.apply($, [def1, def2])

Es lo mismo que:

$.when(def1, def2)

Pero la forma de llamada aplicada le permite pasar una serie de parámetros desconocidos. (En su código, está diciendo que los datos provienen de un servicio, entonces esa es la única forma de llamar $ .when )


developer.mozilla.org/en-US/docs/JavaScript/Reference/… se usa para llamar a una función con una matriz de argumentos. Toma cada elemento de la matriz y usa cada uno como un parámetro para la función. .apply también puede cambiar el contexto ( this ) dentro de una función.

Entonces, tomemos $.when . Se usa para decir "cuando todas estas promesas se resuelvan ... hagan algo". Toma un número infinito (variable) de parámetros.

En tu caso, tienes una variedad de promesas; no sabe cuántos parámetros está pasando a $.when . Pasar la matriz a $.when no funcionaría, porque espera que sus parámetros sean promesas, no una matriz.

Ahí es donde .apply entra. Toma la matriz y llama $.when con cada elemento como parámetro (y se asegura de que this esté configurado en jQuery / $ ), entonces todo funciona :-)