Sobre la base del título de la pregunta, "¿Resolver promesas una tras otra (es decir, en secuencia)?", Podríamos entender que el OP está más interesado en el manejo secuencial de las promesas de liquidación que las llamadas secuenciales per se .
Esta respuesta se ofrece:
- para demostrar que las llamadas secuenciales no son necesarias para el manejo secuencial de las respuestas.
- para exponer patrones alternativos viables a los visitantes de esta página, incluido el OP si aún está interesado más de un año después.
- a pesar de la afirmación del OP de que no quiere hacer llamadas al mismo tiempo, lo cual puede ser realmente el caso, pero igualmente puede ser una suposición basada en el deseo de un manejo secuencial de las respuestas como lo implica el título.
Si realmente no se desean llamadas concurrentes, vea la respuesta de Benjamin Gruenbaum que cubre las llamadas secuenciales (etc.) de manera integral.
Sin embargo, si está interesado (para mejorar el rendimiento) en patrones que permiten llamadas simultáneas seguidas de un manejo secuencial de las respuestas, siga leyendo.
Es tentador pensar que tiene que usar Promise.all(arr.map(fn)).then(fn)
(como lo he hecho muchas veces) o un azúcar elegante de Promise lib (especialmente Bluebird), sin embargo (con crédito a este artículo ) un arr.map(fn).reduce(fn)
patrón hará el trabajo, con las ventajas de que:
- funciona con cualquier lib de promesa, incluso versiones precompatibles de jQuery, solo
.then()
se usa.
- ofrece la flexibilidad de omitir el error o detener el error, lo que quieras con un mod de una línea.
Aquí está, escrito para Q
.
var readFiles = function(files) {
return files.map(readFile) //Make calls in parallel.
.reduce(function(sequence, filePromise) {
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//skip-over-error. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
Nota: solo ese fragmento, Q()
es específico de Q. Para jQuery, debe asegurarse de que readFile () devuelva una promesa de jQuery. Con las bibliotecas A +, las promesas extranjeras se asimilarán.
La clave aquí es la sequence
promesa de la reducción , que secuencia el manejo delreadFile
promesas pero no su creación.
Y una vez que haya absorbido eso, ¡tal vez sea un poco alucinante cuando se dé cuenta de que el .map()
escenario no es realmente necesario! Todo el trabajo, llamadas paralelas más manejo en serie en el orden correcto, se puede lograr reduce()
solo, más la ventaja adicional de una mayor flexibilidad para:
- Convierta de llamadas asíncronas paralelas a llamadas asíncronas en serie simplemente moviendo una línea, potencialmente útil durante el desarrollo.
Aquí está, para Q
otra vez.
var readFiles = function(files) {
return files.reduce(function(sequence, f) {
var filePromise = readFile(f);//Make calls in parallel. To call sequentially, move this line down one.
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//Skip over any errors. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
Ese es el patrón básico. Si también quisiera entregar datos (por ejemplo, los archivos o alguna transformación de ellos) a la persona que llama, necesitaría una variante leve.