Exécutez un lot de promesses en série. Une fois Promise.all est fait, passez au prochain lot

J'ai un tableau qui contient une série de promesses, et chaque tableau intérieur pourrait avoir des promesses de 4k, 2k ou 500.

Au total, il y a environ 60k promesses et je peux le tester avec d'autres valeurs aussi.

Maintenant, je dois exécuter Promise.all (BigArray [0]).

Une fois que le premier ensemble interne est terminé, je dois exécuter la prochaine Promise.all (BigArray [1]) et ainsi de suite.

Si j'essaie d'exécuter une Promise.all (BigArray), il lance:

Erreur fatale call_and_retry_2 allocation échouée – traitement hors mémoire J'ai besoin de l'exécuter chaque promesse en série, pas en parallèle, ce que je pense que c'est ce que Node fait. Je ne devrais pas utiliser de nouvelles libs, mais je suis prêt à considérer la réponse!

Modifier:

Voici un exemple de code:

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; }) } 

Votre question est un peu méconnue qui peut avoir confondu certaines personnes dans cette question et dans la version précédente de cette question. Vous essayez d'exécuter un lot d'opérations asynchrones en série, un lot d'opérations, puis, lorsque cela se fait, exécutez un autre lot d'opérations. Les résultats de ces opérations asynchrones sont suivis avec des promesses. Les promesses elles-mêmes représentent des opérations asynchrones qui ont déjà été lancées. Les «promesses» ne sont pas exécutées elles-mêmes. Donc techniquement, vous ne "exécutez pas un lot de promesses en série". Vous exécutez un ensemble d'opérations, tracez leurs résultats avec des promesses, puis exécutez le lot suivant lorsque le premier lot est terminé.

Quoi qu'il en soit, voici une solution à la sérialisation de chaque lot d'opérations.

Vous pouvez créer une fonction interne que j'appelle habituellement next() qui vous permet de traiter chaque itération. Lorsque la promesse résout de traiter un innerArray, vous appelez next() nouveau:

 function mainFunction() { return new Promise(function(resolve, reject) { var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; //the summ of all arguments is over 60k... var results = []; var index = 0; function next() { if (index < bigArray.length) { getInfoForEveryInnerArgument(bigArray[index++]).then(function(data) { results.push(data); next(); }, reject); } else { resolve(results); } } // start first iteration next(); }); } 

Cela rassemble également tous les sous-résultats dans un tableau de résultats et renvoie une promesse principale qui est la valeur résolue est ce tableau de résultats. Donc, vous pouvez utiliser ceci comme:

 mainFunction().then(function(results) { // final results array here and everything done }, function(err) { // some error here }); 

Vous pouvez également utiliser le motif de conception .reduce() pour itérer un tableau en série:

 function mainFunction() { var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; return bigArray.reduce(function(p, item) { return p.then(function(results) { return getInfoForEveryInnerArgument(item).then(function(data) { results.push(data); return results; }) }); }, Promise.resolve([])); } 

Cela crée plus de promesses simultanées que la première option et je ne sais pas si c'est un problème pour une grande série de promesses (c'est pourquoi j'ai offert l'option d'origine), mais ce code est plus propre et le concept est pratique à utiliser Pour d'autres situations aussi.


FYI, il existe des fonctionnalités complémentaires prometteuses conçues pour ce faire pour vous. Dans la bibliothèque de promesses Bluebird (qui est une excellente bibliothèque pour le développement à l'aide de promesses), ils ont Promise.map() qui est conçu pour cela:

 function mainFunction() { var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; return Promise.map(bigArray, getInfoForEveryInnerArgument); } 

Vous pouvez le faire de manière récursive, par exemple ici, je devais mettre environ 60k documents en mongo, mais c'était trop grand pour le faire en une seule étape, donc je prends des documents 1k, les envoie au mongo, après avoir fini, je prends D'autres documents 1k, etc.

 exports.rawRecursive = (arr, start) => { //ending condition if (start > arr.length) { return; } Rawmedicament.insertManyAsync(_.slice(arr, start, start + 1000)).then(() => { //recursive exports.rawRecursive(arr, start + 1000); }); }; 

Si vous souhaitez remarquer, lorsque tout est terminé, vous pouvez mettre fin au rappel ou si vous aimez Promises, vous pouvez appeler resolve ().

En outre, si le tableau d'origine n'est pas une promesse, mais des objets qui doivent être traités, le traitement par lots peut être effectué sans une dépendance externe à l'aide de la combinaison de Array.prototype.map() , Array.prototype.slice() et Promise.all() :

 // Main batch parallelization function. function batch(tasks, pstart, atonce, runner, pos) { if (!pos) pos = 0; if (pos >= tasks.length) return pstart; var p = pstart.then(function() { output('Batch:', pos / atonce + 1); return Promise.all(tasks.slice(pos, pos + atonce).map(function(task) { return runner(task); })); }); return batch(tasks, p, atonce, runner, pos + atonce); } // Output function for the example function output() { document.getElementById("result").innerHTML += Array.prototype.slice.call(arguments).join(' ') + "<br />"; window.scrollTo(0, document.body.scrollHeight); } /* * Example code. * Note: Task runner should return Promise. */ function taskrunner(task) { return new Promise(function(resolve, reject) { setTimeout(function() { output('Processed:', task.text, 'Delay:', task.delay); resolve(); }, task.delay); }); } var taskarray = []; function populatetasks(size) { taskarray = []; for (var i = 0; i < size; i++) { taskarray.push({ delay: 500 + Math.ceil(Math.random() * 50) * 10, text: 'Item ' + (i + 1) }); } } function clean() { document.getElementById("result").innerHTML = ''; } var init = Promise.resolve(); function start() { var bsize = parseInt(document.getElementById("batchsize").value, 10), tsize = parseInt(document.getElementById("taskssize").value, 10); populatetasks(tsize); init = batch(taskarray.slice() /*tasks array*/ , init /*starting promise*/ , bsize /*batch size*/ , taskrunner /*task runner*/ ); } 
 <input type="button" onclick="start()" value="Start" /> <input type="button" onclick="clean()" value="Clear" />&nbsp;Batch size:&nbsp; <input id="batchsize" value="4" size="2"/>&nbsp;Tasks:&nbsp; <input id="taskssize" value="10" size="2"/> <pre id="result" />