1

The title speaks for itself, i am looking into tw ways to call a db function from an array of models to process

here is what i had

for(const x in arr ) {
   await insertIntoDB(x);
}

but i was told by someone that this is handling them async and it much better performce and faster

const promises = [];

for(const x of arr ) {
  promises.push( insertIntoDB() );
}

await Promise.all(promises);

or

await Promise.all(async arr.map(async x => insertIntoDB(x)));

I know js does not do true paralle operations but it does do it concurrently, so is there really any difference in calling the await wwithin al oop vs waiting till end? will they be processed in order or concurrently saving time?

Tanner Summers
  • 689
  • 1
  • 8
  • 26
  • In loop, they execute sequentially, with `Promise.all` they execute all at once (api requests can happen in parallel for example) – Konrad Feb 22 '23 at 22:53

3 Answers3

1

Please have a look at the answers under: Any difference between await Promise.all() and multiple await?.

By using for...of you would be executing promises in sequence, while if you use Promise.all you will run them in parallel, and you will get Promise.all's ability to fail-fast, which will stop if any of your promises fail.

However, in your example with insertIntoDB, I think you can do better by using a bulk or batch insertion in the database and then delegating this parallelism to the DBMS and only processing the response on Node.js (possibly as one promise), going for either of the two approaches means that you will be hitting the database multiple times for something that could be done in one batch.

Fcmam5
  • 4,888
  • 1
  • 16
  • 33
0

There is a difference: without await, the database API will get new requests even while it is still processing earlier requests. It then depends on how well that database engine can deal with concurrent requests. Some engines might only consider a next request when the current one has been completed, meaning that on the client side there is hardly any gain: the client side didn't queue the promise creation, but the database still queued the requests. Even though all promises were created in one go, the time between resolving promises will then be similar to what happens in the await variant.

When the database engine does perform the actions in a concurrent way, you might have a gain by not using await. It might also be that these concurrent actions will make the database engine use a lot of resources (CPU load, memory), and at some point that might still slow things down.

So, it all depends on how the non-JavaScript part (the database engine) handles multiple requests.

You are right that at the JavaScript side there is no concurrency in either solution. It is the non-JavaScript part of the database API that could provide good concurrency.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thanks for this @trincot, I also wanted to add/ask, for using Promise.All, does it resolve in any order? or does it wait in order for each resolve before finishing? – Tanner Summers Feb 22 '23 at 23:18
  • `Promise.all` doesn't influence the promises that it has been given (it doesn't resolve the given promises). It merely returns a new promise, which will resolve when all the given promises have resolved, and it fulfils with a value that is an array that holds the fulfilment values for each of the given promises, in the order that the promises were given. If any of the promises rejects, then also the newly created promise will reject. – trincot Feb 23 '23 at 07:03
  • Make sense @trincot, to follow up, if you have 5 promises for this promise.all, if we do a loop and put all 5 promises to make this new promise. And let's say promise 3&5 resolves before promise 1&2, will promise.all wait for the first promise to resolve before caring about the ones after? I guess I'm a bit lost on if the order on which the prose's resolve matter to promise.all. if it does or doesn't the overall time theoretically could be same as if u waited for each one individually in the loop? – Tanner Summers Feb 23 '23 at 17:10
  • The new promise will stay in a pending state while there is at least one of the given promises pending. So in your example, if 3 and 5 are resolved, the new promise will still be pending. Only when 1 & 2 and 4 are also resolved, will the status of the new promise also transition to resolved. The order in which the promises resolve is not relevant. Whichever happens to be the last one to resolve -- at that time will the new promise resolve also. It is not trivial to wait for each one to resolve in a loop -- assuming all promises were **created together**. `Promise.all` does that job for you. – trincot Feb 23 '23 at 17:17
0

Interesting question.

Loop pros:

  • In the loop you could break it to save further processing.
  • It less code
  • It can be dynamically driven

Loop cons:

  • Its not pure.
  • It feels like its an anti pattern and risking perpetual loop compounded by delayed callbacks (though the end result it is no different from running several of them one after the other)
  • Its harder to debug single lines
  • You have no variable to play with outside the loop for referencing anything.

Curious why not do this to make it more pure and reusable:

const promises = arr.map(x => insertIntoDB(x))
// can debug each promise singly before waiting for them all

Promise.allSettled(promises).then(resp=> {
// do something with resp
})

Also curious why you would insert into a db a single line at a time when you can send multiple in one post to save hitting server so many times.

Steve Tomlin
  • 3,391
  • 3
  • 31
  • 63
  • hey @Steve Tomlin, its not the best example, in reality the code is other async functions that may be doing multiple db operations at once. I tried to keep it high level in order to graps if it is better in some perforamce wise to do some I/O or db operaiton awaiting per loop, or doing it in a promise.all since i been told the latter is faster but i wanted to verify – Tanner Summers Feb 22 '23 at 23:28