Given a method which takes an array of items, a batchSize and a method which turns 1 item into a promise, you can simply batch them up and await
the result
const batchPromisify = async (arr, batchSize, makePromise) => {
while(arr.length) {
const batch = arr.splice(0,batchSize);
const promises = batch.map(makePromise);
await Promise.all(promises);
}
}
Here is a live example with an array of integers, and an async method which just simulates a short delay. You can see that the makePromise
callback passed in just wraps the integer from the array in a delay followed by a console log saying that item is complete. I have also wrapped the call to the batch with console logs so you can see that it is running 10 at a time in this example:
const delay = (ms) => new Promise(resolve => setTimeout(resolve,ms));
const items = new Array(100).fill(0).map ( (_,i) => i);
const batchPromisify = async (arr, batchSize, makePromise) => {
while(arr.length) {
const batch = arr.splice(0,batchSize);
const promises = batch.map(makePromise);
console.log("starting batch")
await Promise.all(promises);
console.log("finished batch")
}
}
batchPromisify(items, 10, i => delay(100).then(_ => console.log("finished", i)));
Using this with your code would look something like
batchPromisify(simIds, 50,
simId => simService.getSimcardBasedonAction(userid, [simid], action))
There is no need to wrap your call in another Promise
as getSimcardBasedonAction
already returns one!
Now say you wwanted to get the results out afterwards, there is a small change that can be made to batchPromisify
:
const delay = (ms) => new Promise(resolve => setTimeout(resolve,ms));
const items = new Array(100).fill(0).map ( (_,i) => i);
const batchPromisify = async (arr, batchSize, makePromise) => {
const results = [];
while(arr.length) {
const batch = arr.splice(0,batchSize);
const promises = batch.map(makePromise);
results.push(await Promise.all(promises));
}
return results;
}
(async function(){
const result = await batchPromisify(items, 10, i => delay(100).then(_ => i.toString()));
console.log(result.flat());
})();
Note in this case I have had to await
the call to batchPromisify
, and I changed the makePromise
return the string equivalent of the integer for demonstration purposes. The result of the call is an array of arrays, representing each batch and the results therein. You can always use .flat()
to flatten this array if you want all the results in 1 array.
Now your code would be
const results = await batchPromisify(simIds, 50,
simId => simService.getSimcardBasedonAction(userid, [simid], action));
const flatResults = results.flat();