Solución:
Es bastante sencillo con algunas reglas simples:
-
Siempre que crea una promesa en un
then
, devolverlo – Cualquier promesa que no devuelva no se esperará afuera. -
Siempre que cree varias promesas,
.all
ellos – De esa forma espera todas las promesas y no se silencia ningún error de ninguna de ellas. -
Siempre que anidas
then
s, normalmente puede volver a la mitad –then
las cadenas suelen tener como máximo 1 nivel de profundidad. - Siempre que realice IO, debería ser con una promesa – O debe ser una promesa o debe usar una promesa para señalar su finalización.
Y algunos consejos:
-
El mapeo se hace mejor con
.map
que confor/push
– si está mapeando valores con una función,map
le permite expresar de manera concisa la noción de aplicar acciones una por una y agregar los resultados. -
La simultaneidad es mejor que la ejecución secuencial si es gratis – es mejor ejecutar las cosas al mismo tiempo y esperarlas
Promise.all
que ejecutar las cosas una tras otra, cada una esperando antes que la siguiente.
Ok, comencemos:
var items = [1, 2, 3, 4, 5];
var fn = function asyncMultiplyBy2(v){ // sample async action
return new Promise(resolve => setTimeout(() => resolve(v * 2), 100));
};
// map over forEach since it returns
var actions = items.map(fn); // run the function over all items
// we now have a promises array and we want to wait for it
var results = Promise.all(actions); // pass array of promises
results.then(data => // or just .then(console.log)
console.log(data) // [2, 4, 6, 8, 10]
);
// we can nest this of course, as I said, `then` chains:
var res2 = Promise.all([1, 2, 3, 4, 5].map(fn)).then(
data => Promise.all(data.map(fn))
).then(function(data){
// the next `then` is executed after the promise has returned from the previous
// `then` fulfilled, in this case it's an aggregate promise because of
// the `.all`
return Promise.all(data.map(fn));
}).then(function(data){
// just for good measure
return Promise.all(data.map(fn));
});
// now to get the results:
res2.then(function(data){
console.log(data); // [16, 32, 48, 64, 80]
});
Aquí hay un ejemplo simple usando reducir. Se ejecuta en serie, mantiene el orden de inserción y no requiere Bluebird.
/**
*
* @param items An array of items.
* @param fn A function that accepts an item from the array and returns a promise.
* @returns {Promise}
*/
function forEachPromise(items, fn) {
return items.reduce(function (promise, item) {
return promise.then(function () {
return fn(item);
});
}, Promise.resolve());
}
Y utilícelo así:
var items = ['a', 'b', 'c'];
function logItem(item) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
console.log(item);
resolve();
})
});
}
forEachPromise(items, logItem).then(() => {
console.log('done');
});
Nos ha resultado útil enviar un contexto opcional en bucle. El contexto es opcional y compartido por todas las iteraciones.
function forEachPromise(items, fn, context) {
return items.reduce(function (promise, item) {
return promise.then(function () {
return fn(item, context);
});
}, Promise.resolve());
}
Su función de promesa se vería así:
function logItem(item, context) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
console.log(item);
context.itemCount++;
resolve();
})
});
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)