Saltar al contenido

Node JS Promise.all y forEach

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 thens, normalmente puede volver a la mitadthen 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 con for/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)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *