2

Let's say I want to run a lot of promises (which are not yet declared, so their body has not executed yet). I don't want to run them in sequence because that would be very slow but I don't want all of them to run in parallel because that would overload the server. Each of this promises can be resolve or rejected very fast (around 1 second) or, in the worst case scenario, after something around 40 seconds. None of the promises depend on the result of any other. Which is the best way to handle this case? I have seen that an alternative is using Promise.all() in batches of 10 promises. However, the latter doesn't seem to be efficient considering that I can have 9 promises resolving very fast, but 1 of them resolving very slow. What I would like the following:

Say I have 100 promises. I start processing 10 of them, as soon as one of them resolves, the 11th promise is processed, as soon as other one resolves, the 12th promise is processed, and so on. Notice this behavior is different from using Promise.all() in batches of 10 because in that case the 11th to 20th promise would be processed after all of the 1st to 10th promises are resolved.

Which is the best way of implementing this? I was picturing something like having a queue and having an async function processPromise that pops promises from that queue (until it is empty) and process them. I would then make an array of promises where each promise corresponds to an invocation of processPromise and then Promise.all() over that array. However, I'm not sure if concurrent access to that queue (that is share by different invocations of processPromise) would be an issue, or if I have nothing to worry about considering javascript is single-threaded.

9
  • Why do you need to execute the promises in batches? Commented Mar 14, 2022 at 3:49
  • Would this work? npmjs.com/package/p-limit Commented Mar 14, 2022 at 3:51
  • 1
    Promise.all will reject immediately if any input promise rejecting so it might not be suitable for this case. Have you tried Promise.allSettled? Commented Mar 14, 2022 at 3:52
  • 2
    "I have an array with promises" - if you got that far, you already have started all of the tasks for whose results you got the promises for, and they are already running - presumably in parallel - without any way to affect that. Commented Mar 14, 2022 at 4:07
  • 1
    @Bergi yeah, I might have use a bad wording, what I have is an array of data that I'm going to use to build the promises. I'm aware that the tasks start when the promises are constructed. Thanks for the comment, I'll edit the post to make that clear :) Commented Mar 14, 2022 at 4:17

1 Answer 1

0

I have used promise-pool for this:

 const { results } = await PromisePool.withConcurrency(10) .for(tasks) .process(async task => { const result = await this.longTask(task); return { result }; }); 

Note that surprisingly results are not always returned in the order you provided them, so depending on your use case you may have to track the original index and sort upon completion:

 const tasks = items.map((item, index) => ({ item, index })); const { results } = await PromisePool.withConcurrency(10) .for(tasks) .process(async task => { const result = await this.longTask(task.item); return { result, index: task.index }; }); const ordered = results .sort((a, b) => a.index - b.index) .map(result => result.result); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.