2016-05-13 7 views
7

У меня есть массив, содержащий массив обещаний, и каждый внутренний массив может иметь либо 4k, 2k, либо 500 обещаний.Выполнение серии обещаний в серии. После выполнения Promise.all перейдите к следующей партии

Всего существует около 60 тыс. Обещаний, и я могу проверить его на другие значения.

Теперь мне нужно выполнить Promise.all (BigArray [0]).

Как только первый внутренний массив будет выполнен, мне нужно выполнить следующий Promise.all (BigArray [1]) и т. Д. И т. Д.

Если я пытаюсь выполнить Promise.all (BigArray) его метание:

распределения фатальных call_and_retry_2 ошибки не удались - процесс из памяти мне нужно выполнить его каждый из обещаний в серии, а не параллельно, которые я Думаю, это то, что Узел делает. Я не должен использовать новые библиотеки, но я готов рассмотреть ответ !.

Edit:

Вот пример кусок кода:

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

Вы тот же пользователь, который разместил этот предыдущий вопрос, который содержит какой-то соответствующий контекст: [Выполнить Promise.all в серии] (http://stackoverflow.com/questions/37196699/execute-promise-all-in-series/37196780# comment61956748_37196780)? – jfriend00

+0

Вы в порядке, когда все операции 60k выполняются параллельно, но вы просто хотите обрабатывать результаты поочередно (по одному подматрицу за раз)? Или вам действительно нужны операции, которые каждый вспомогательный массив представляет для серийного запуска и обработки? Последнее было бы намного безопаснее с точки зрения памяти и ресурсов в node.js. – jfriend00

+0

Да, я. Мне нужно, чтобы они бежали последовательно. все в порядке, только параллельные обещания innerArray работают параллельно. Как только innerArray 1 будет выполнен, переходите к следующим обещаниям 500-4k на innerArray 2 и запускайте их параллельно, после того, как обещания innnerArray 500-4k завершаются, перейдите к innerArray 3 и сделайте эти 500-4k, как только будет выполнено внутреннее перемещение 3 на innerArray 4 и делать эти 500-4k ... и т. д. – user1554966

ответ

6

Ваш вопрос немного неназванный, что, возможно, путало некоторых людей в этом вопросе и в предыдущей версии этого вопроса. Вы пытаетесь выполнить партию асинхронных операций последовательно, одну партию операций, а затем, когда это будет выполнено, выполните другую партию операций. Результаты этих асинхронных операций отслеживаются с обещаниями. Сами обещания представляют собой асинхронные операции, которые уже были запущены. «Обещания» не исполняются сами. Так что технически вы не выполняете серию обещаний в серии. Вы выполняете набор операций, отслеживаете их результаты с помощью обещаний, а затем выполняете следующую партию, когда выполняется первая партия.

В любом случае, это решение для сериализации каждой партии операций.

Вы можете создать внутреннюю функцию, которую я обычно вызываю next(), которая позволяет обрабатывать каждую итерацию. Когда обещание решает от обработки одного 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(); 
    }); 
} 

Это также собирает все вложенные результаты в массив результатов и возвращает мастер обещание кто разрешенное значение это приводит массив.Таким образом, вы могли бы использовать это как:

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

Вы также можете использовать шаблон .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([])); 
} 

Это создает более одновременные обещания, чем первый вариант, и я не знаю, является ли это проблемой для такого большого набора обещаний (именно поэтому я предложил оригинальный вариант), но этот код более чист, и концепция удобна для других ситуаций.


FYI Есть некоторые возможности надстройки, созданные для этого. В Bluebird promise library (что большая библиотека для разработки с использованием обещаний), они имеют Promise.map(), который сделал для этого:

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

} 
0

Вы можете сделать это рекурсивно, например, здесь мне нужно было поставить около 60k документов в Монго, но он был слишком большим, сделать это за один шаг, поэтому я беру 1k документы, отправить их на Монго, после того, как он закончил, я беру еще 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() там.

0

Кроме того, если исходный массив не обещаний, но объекты, которые должны быть обработаны, пакетным обработка может быть сделано без внешней зависимости с использованием комбинации Array.prototype.map(), Array.prototype.slice() и 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" />

+0

См. [первая редакция] (http://stackoverflow.com/revisions/40850909/1) для нерекурсивной версии 'batch'. – Annarfych

 Смежные вопросы

  • Нет связанных вопросов^_^