javascript - then - Bucle asíncrono de jQuery Aplazados(promesas)
jquery submit promise (5)
Desafío interesante por cierto. Lo que he encontrado es una función recursiva que acepta una lista y un índice de inicio opcional.
Aquí hay un enlace al jsFiddle que he probado con diferentes intervalos e intervalos de lista.
Supongo que tiene una lista de funciones que devuelven promesas (no una lista de números). Si tiene una lista de números, cambiaría esta parte.
$.when(tasks[index]()).then(function(){
deferredSequentialDo(tasks, index + 1);
});
a esto
/* Proxy is a method that accepts the value from the list
and returns a function that utilizes said value
and returns a promise */
var deferredFunction = myFunctionProxy(tasks[index]);
$.when(tasks[index]()).then(function(){
deferredSequentialDo(tasks, index + 1);
});
No estoy seguro de qué tan grande podría ser su lista de funciones, pero tenga en cuenta que el navegador conservará los recursos de la primera llamada de Aplazado de Diferencias de Diferencias hasta que estén terminadas.
Estoy tratando de crear lo que creo que se conoce como una "cascada". Quiero procesar secuencialmente una serie de funciones asíncronas (jQuery promete).
Aquí hay un ejemplo artificial:
function doTask(taskNum){
var dfd = $.Deferred(),
time = Math.floor(Math.random()*3000);
setTimeout(function(){
console.log(taskNum);
dfd.resolve();
},time)
return dfd.promise();
}
var tasks = [1,2,3];
for (var i = 0; i < tasks.length; i++){
doTask(tasks[i]);
}
console.log("all done");
Me gustaría que completara la tarea en el orden en que se ejecutan (presente en la matriz). Entonces, en este ejemplo, quiero que haga la tarea 1 y espere a que se resuelva, luego haga la tarea 2, espere a que se resuelva, haga la tarea 3, etc. y el registro "todo listo".
Tal vez esto sea realmente obvio, pero he estado tratando de resolver esto toda la tarde.
Eche un vistazo a los métodos de $.when y then para ejecutar diferidos.
Las cascadas se utilizan para canalizar los valores de retorno de uno a otro, en serie. Se vería algo como esto .
function doTask (taskNum) {
var dfd = $.Deferred(),
time = Math.floor(Math.random() * 3000);
console.log("running task " + taskNum);
setTimeout(function(){
console.log(taskNum + " completed");
dfd.resolve(taskNum + 1);
}, time)
return dfd.promise();
}
var tasks = [1, 2, 3];
tasks
.slice(1)
.reduce(function(chain) { return chain.then(doTask); }, doTask(tasks[0]))
.then(function() { console.log("all done"); });
Tenga en cuenta el argumento pasado para resolve
. Eso pasa a la siguiente función en la cadena. Si solo desea ejecutarlos en serie sin canalizar los argumentos, puede eliminar eso y cambiar la reducción de llamada a .reduce(function(chain, taskNum) { return chain.then(doTask.bind(null, taskNum)); }, doTask(tasks[0]));
Y en paralelo se vería así :
var tasks = [1,2,3].map(function(task) { return doTask(task); });
$.when.apply(null, tasks).then(function() {
console.log(arguments); // Will equal the values passed to resolve, in order of execution.
});
Intentaría usar la $().queue
lugar de $.Deferred
aquí. Agregue las funciones a una cola y solo llame a la siguiente cuando esté listo.
function doTask(taskNum, next){
var time = Math.floor(Math.random()*3000);
setTimeout(function(){
console.log(taskNum);
next();
},time)
}
function createTask(taskNum){
return function(next){
doTask(taskNum, next);
}
}
var tasks = [1,2,3];
for (var i = 0; i < tasks.length; i++){
$(document).queue(''tasks'', createTask(tasks[i]));
}
$(document).queue(''tasks'', function(){
console.log("all done");
});
$(document).dequeue(''tasks'');
Para una cascada, necesitas un bucle asíncrono:
(function step(i, callback) {
if (i < tasks.length)
doTask(tasks[i]).then(function(res) {
// since sequential, you''d usually use "res" here somehow
step(i+1, callback);
});
else
callback();
})(0, function(){
console.log("all done");
});
Puede crear un $ .Deferred resuelto y simplemente agregarlo a la cadena con cada iteración:
var dfd = $.Deferred().resolve();
tasks.forEach(function(task){
dfd = dfd.then(function(){
return doTask(task);
});
});
Paso a paso ocurre lo siguiente:
//begin the chain by resolving a new $.Deferred
var dfd = $.Deferred().resolve();
// use a forEach to create a closure freezing task
tasks.forEach(function(task){
// add to the $.Deferred chain with $.then() and re-assign
dfd = dfd.then(function(){
// perform async operation and return its promise
return doTask(task);
});
});
Personalmente, me parece más limpio que la recursión y más familiar que $ (). Queue (jQuery API for $ (). La cola es confusa ya que está diseñada para animaciones, también es probable que esté usando $ .Deferred''s en otros lugares en su código). También tiene los beneficios de la transferencia estándar de resultados a través de la resolución () en la operación asíncrona y permite la conexión de una propiedad de $ .done.
Aquí está en un jsFiddle