sbmthakur
sbmthakur

Reputation: 165

How much is the performance overhead for awaiting an already fulfilled Promise?

While doing code reviews, I've recently come across such kind of code blocks:

const promises = [];
const data = [];
for (let piece of pieces) {
  for (let chunk of piece) {
    promises.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
  }
  data = await Promise.all(promises);
}

Here pieces is an array of arrays. Note that due to certain constraints we cannot await all Promises at once, hence this sort of chunking.

In my feedback, I write that this appears to be an anti-pattern as we are also awaiting Promises which were resolved in the previous iterations and the following is the proper way of handling such scenarios:

const data = [];
for (let piece of pieces) {
  const promises = [];
  for (let chunk of piece) {
    promies.push(execute(chunk)); //execute returns a promise which is not yet fulfilled
  }
  data.push(... await Promise.all(promises));
}

At the end, data will be the same in both cases.

I understand how data is being populated in both cases. I would like to know how much is the performance overhead of awaiting an already fulfilled promise (which is happening in the first code block) and is it significant?

Upvotes: 6

Views: 1352

Answers (1)

Bergi
Bergi

Reputation: 665584

The overhead is minuscule - it needs to iterate the already fulfilled promise, inspect it, take out the data and put it inside the result array. Assuming native promises, I expect this to be optimised and not need a roundtrip to the event loop, if you had thenables in the array then all of them would need to get resolved to a promise and that promise would need to be awaited asynchronously, taking a toll on the promise job queue.

The overhead in processing time will not be significant compared to the actual asynchronous work done in your execute function.

However, no matter how small the overhead is, the issue with the first version of your code is that its runtime complexity is quadratic: Promise.all needs to iterate the whole promises array every time. The more chunks * pieces you have, the more pronounced the effect will be. I agree with your review feedback and would recommend the second version of the code.

Upvotes: 1

Related Questions