Tengo una matriz que contiene una variedad de promesas, y cada matriz interna podría tener 4k, 2k o 500 promesas.

En total, hay alrededor de 60k promesas y también puedo probarlo con otros valores.

Ahora necesito ejecutar el Promise.all(BigArray[0]).

Una vez que se realiza la primera matriz interna, necesito ejecutar la siguiente Promise.all(BigArray[1]) y así sucesivamente.

Si trato de ejecutar un Promise.all(BigArray) su lanzamiento:

error fatal error en la asignación de call_and_retry_2 - proceso sin memoria

Necesito ejecutar cada una de las promesas en serie, no en paralelo, lo que creo que es lo que está haciendo Node. ¡No debería usar nuevas bibliotecas, sin embargo, estoy dispuesto a considerar la respuesta!

Editar:

Aquí hay un ejemplo de código:

function getInfoForEveryInnerArgument(InnerArray) {
    const CPTPromises = _.map(InnerArray, (argument) => getDBInfo(argument));
    return Promise.all(CPTPromises)
        .then((results) => {
            return doSomethingWithResults(results);
        });
}
function mainFunction() {
    BigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....];
    //the summ of all arguments is over 60k...
    const promiseArrayCombination = _.map(BigArray, (InnerArray, key) => getInfoForEveryInnerArgument(InnerArray));

    Promise.all(promiseArrayCombination).then((fullResults) => {
        console.log(fullResults);
        return fullResults;
    })
}
4
Rodrigo Zurek 12 may. 2016 a las 23:20

5 respuestas

La mejor respuesta

Promise.all no funcionará, puede usar Array.reduce para procesar elementos BigArray, uno por uno:

BigArray.reduce((promiseChain, currentArray) => {
    return promiseChain.then(chainResults =>
        Promise.all(currentArray).then(currentResult =>
            [...chainResults, currentResult]
        )
    );
}, Promise.resolve([])).then(arrayOfArraysOfResults => {
    // Do something with all results
});
2
greuze 24 may. 2018 a las 09:57

La prometedora biblioteca bluebird ofrece un método auxiliar llamado Promise.map, que toma una matriz o una promesa de una matriz como primer argumento y asigna todos sus elementos a una matriz de resultados, que a su vez También se le promete. Tal vez podrías probar algo como esto:

return Promise.map(BigArray, function(innerArray) {
  return Promise.all(innerArray);
})
.then(function(finishedArray) {
  // code after all 60k promises have been resolved comes here
  console.log("done");
});

Pero como ya se dijo anteriormente, esta sigue siendo una tarea muy intensa en recursos que puede consumir toda la memoria disponible.

0
SaSchu 12 may. 2016 a las 20:42

Buena respuesta aquí Devolución de llamada después de que todas las devoluciones de llamada asincrónicas se hayan completado

function asyncFunction (item, cb) {
  setTimeout(() => {
    console.log('done with', item);
    cb(item*10);
  }, 1000*item);
}



let requests = [1,2,3].map((item) => {
    return new Promise((resolve) => {
      asyncFunction(item, resolve);
    });
})

Promise.all(requests).then(
//  () => console.log('done')
    function(arr){
        console.log(arr)
         console.log('done')
    }
    );
0
Community 23 may. 2017 a las 12:22

Bastante simple de lograr con async / await en ES2017:

(async () => {
    for (let i = 0; i < BigArray.length; i++) {
        await Promise.all(BigArray(i));
    }
})();
2
maksim 29 ago. 2018 a las 04:43

Promise.all() verificará cada uno de los resultados de su promesa que se pasan como argumentos en paralelo , y se rechazará al primer error, o se resolverá al completar todas las promesas.

Del MDN:

Promise.all pasa una matriz de valores de todas las promesas en el objeto iterable que se pasó. La matriz de valores mantiene el orden del objeto iterable original, no el orden en que se resolvieron las promesas. Si algo pasado en la matriz iterable no es una promesa, Promise.resolve lo convierte en uno.

Si cualquiera de las promesas aprobadas se rechaza, la Promesa completa se rechaza inmediatamente con el valor de la promesa que rechazó, descartando todas las demás promesas, ya sea que se hayan resuelto o no. Si se pasa una matriz vacía, este método se resuelve de inmediato.

Si necesita ejecutar todas sus promesas en serie, entonces el método Promise.all() no funcionará para su aplicación. En cambio, necesita encontrar un enfoque iterativo para resolver sus promesas. Esto va a ser difícil; node.js es de naturaleza asíncrona, y el uso de bucles (según mi conocimiento y experiencia) no se bloqueará hasta que se reciba una respuesta de una promesa dentro de un bucle.

Editar:

Existe una biblioteca llamada promise-series-node, que creo que puede ayudarlo bastante aquí. Como ya tiene las promesas creadas, puede pasarle su BigArray:

promiseSeries(BigArray).then( (results) => {
   console.log(results);
});

En mi opinión personal, su enfoque de comenzar con más de 60k promesas no solo tomará una cantidad considerable de tiempo, sino también recursos en el sistema que las ejecuta (es por eso que se está quedando sin memoria). Creo que es posible que desee considerar una mejor arquitectura para la aplicación.

Edit2, ¿Qué es una promesa ?: :

Una promesa representa el resultado de una operación asincrónica, que puede tomar uno de tres estados:

  1. Pendiente: el estado inicial de la promesa
  2. Cumplido: estado de promesa representado por una operación exitosa
  3. Rechazado: estado de promesa representado por una operación fallida

Las promesas son inmutables una vez que se cumplen o se rechazan. Puede encadenar promesas (ideal para evitar repetidas devoluciones de llamadas), así como anidarlas (cuando el cierre es una preocupación). Hay muchos artículos excelentes en la web para esto, aquí es uno que encontré como informativo.

1
Evan Bechtol 13 may. 2016 a las 11:45