Javascript 连续执行一批承诺。承诺完成后,进入下一批

Javascript 连续执行一批承诺。承诺完成后,进入下一批,javascript,node.js,promise,batching,Javascript,Node.js,Promise,Batching,我有一个包含承诺数组的数组,每个内部数组可以有4k、2k或500个承诺 总的来说,大约有6万个承诺,我也可以用其他值来测试它 现在我需要执行Promise.all(BigArray[0]) 完成第一个内部数组后,我需要执行下一个Promise.all(BigArray[1])等等 如果我尝试执行一个Promise.all(BigArray)它抛出: fatal error call_and_retry_2 allocation failed - process out of memory 我需

我有一个包含承诺数组的数组,每个内部数组可以有4k、2k或500个承诺

总的来说,大约有6万个承诺,我也可以用其他值来测试它

现在我需要执行
Promise.all(BigArray[0])

完成第一个内部数组后,我需要执行下一个
Promise.all(BigArray[1])
等等

如果我尝试执行一个
Promise.all(BigArray)
它抛出:

fatal error call_and_retry_2 allocation failed - process out of memory
我需要以串联的方式执行每个承诺,而不是并行的方式,我认为这就是节点所做的。我不应该使用新的LIBS,但是我愿意考虑答案。p> 编辑:

下面是一段示例代码:

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

你可以递归地做,例如,这里我需要在mongo中放置大约60k个文档,但它太大了,无法一步完成,因此我获取1k个文档,将它们发送到mongo,完成后,我获取另外1k个文档,等等

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

如果你想注意到,当所有事情都完成后,你可以在结束条件中放入回调,或者如果你喜欢承诺,你可以在那里调用resolve()。

你的问题有点命名错误,这可能会让这个问题和这个问题的前一个版本中的一些人感到困惑。您正在尝试执行一批串联的异步操作,一批操作,然后执行另一批操作。这些异步操作的结果通过承诺进行跟踪。承诺本身表示已经启动的异步操作。“承诺”本身并没有实现。因此,从技术上讲,你不会“执行一系列的承诺”。执行一组操作,通过承诺跟踪其结果,然后在第一批操作完成后执行下一批操作

无论如何,这里有一个序列化每批操作的解决方案

您可以创建一个内部函数,我通常称之为
next()
,用于处理每次迭代。当promise从处理一个innerArray解析时,再次调用
next()

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

您还可以使用
.reduce()
设计模式串行迭代数组:

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([]));
}
这比第一个选项创建了更多的同时承诺,我不知道这是否是如此大量承诺的问题(这就是我提供原始选项的原因),但这段代码更简洁,并且这个概念也便于在其他情况下使用


仅供参考,有一些promise附加功能专为您设计。在中(这是一个使用promises进行开发的很好的库),他们有
Promise.map()
,它是为此而设计的:

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

}

此外,如果原始数组不是承诺的数组,而是应该处理的对象的数组,则可以使用、和的组合在没有外部依赖的情况下执行批处理:

//主批处理并行化函数。
功能批处理(任务、pstart、atonce、runner、pos){
如果(!pos)pos=0;
如果(pos>=tasks.length)返回pstart;
var p=pstart.then(函数(){
输出(“批次:”,位置/atonce+1);
返回Promise.all(tasks.slice(pos,pos+atonce).map(function(task){
返回跑步者(任务);
}));
});
返回批次(任务、p、atonce、runner、pos+atonce);
}
//以输出函数为例
函数输出(){
document.getElementById(“结果”).innerHTML+=Array.prototype.slice.call(arguments.join)(“”)+“
”; scrollTo(0,document.body.scrollHeight); } /* *示例代码。 *注意:任务运行者应该返回承诺。 */ 函数taskrunner(任务){ 返回新承诺(功能(解决、拒绝){ setTimeout(函数(){ 输出('Processed:',task.text,'Delay:',task.Delay); 解决(); }任务延迟); }); } var taskarray=[]; 函数populatetasks(大小){ taskarray=[]; 对于(变量i=0;i

批量大小:
任务:
只需使用
async/await
reduce
添加到您的答案中即可:

function runPromisesInSeries(bigArray, getInfoForEveryInnerArgument) {
  try {
    return bigArray.reduce(async (acc, cItem) => {
      const results = await acc
      const data = await getInfoForEveryInnerArgument(cItem)
      results.push(data)
      return results
    }, Promise.resolve([]))
  } catch (err) {
    throw err
  }
}
动态批处理更多承诺 一个简单的实现,您可以将一个任务队列批处理为并行运行,并更动态地添加:

类任务队列{
建造师({
制造任务,
initialData=[],
getId=data=>data.id,
batchSize=15,
onComplete=()=>{},
}) {
如果(!makeTask)抛出新错误(“makeTask”参数是必需的”);
this.makeTask=makeTask;
this.getId=getId;
this.batchSize=batchSize;
this.onComplete=onComplete;
this.queue=新映射();
添加(初始数据);
}
添加(…数据){
data.forEach(项=>{
const id=this.getId(项目);
如果(this.queue.has(id))返回;
this.queue.set(id,item);
});
//在创建或添加其他项目时自动运行
this.runNextBatch();
}
runNextBatch(){
如果(this.queueStarted)返回;
如果(this.queue.size==0)返回;
this.queueStarted=true;
const currentBatchData=Array.from(this.queue.values()).slice(0,this.batchSize);
const tasks=currentBatchData.map(数据=>{
const id=this.getId(数据);
//在“makeTask”中实现一些错误处理`
this.makeTask(数据)
.finally(()=>this.queue.delete(id));
});
返回承诺。全部(任务)
.然后(()=>{
this.queuestart=false;
th
function runPromisesInSeries(bigArray, getInfoForEveryInnerArgument) {
  try {
    return bigArray.reduce(async (acc, cItem) => {
      const results = await acc
      const data = await getInfoForEveryInnerArgument(cItem)
      results.push(data)
      return results
    }, Promise.resolve([]))
  } catch (err) {
    throw err
  }
}