-1

How do I make the last console.log line of the code snippet execute only after ALL the updateInkLevel functions finish executing?

  for (let i = 0; i < activeDevices.length; i++) {

    updateInkLevel(accessToken, deviceId, logIndex) 
    await new Promise((r) => setTimeout(r, 500)) // add a small sleep delay
  }
  console.log("everything completed")

updateInkLevel is an async function, returning a promise. I was thinking of using Promise.all, but that would run each iteration in parallel, which is not I want here. Here, I'm firing each iteration sequentially one at a time, with a small sleep delay before firing the next call.

I'm looking for something like Promise.all, but without running in parallel.

References, Is Node.js native Promise.all processing in parallel or sequentially?

tinker
  • 483
  • 4
  • 16
  • 1
    Why not `await updateInkLevel()`? – VLAZ Nov 06 '20 at 09:36
  • hmm.. maybe i could store all the promises returned by updateInkLevel in an array, and call promise all after the loop? – tinker Nov 06 '20 at 09:36
  • Doing (essentially) `Promise.all(allUpdateLinkLevels)` still runs in parallel. – VLAZ Nov 06 '20 at 09:37
  • @VLAZ Per the answer in the reference above, parallel or sequential is determined at time of creation. Promise all simply waits for them to resolve, regardless. – tinker Nov 06 '20 at 13:04
  • It's not *exactly* determined at the time of creation. It depends whether you start a new request before the old one completes. So if you do `request(); request()` that's firing two requests but `await request(); await request()` (or `request().then(() => reqest()`) will first wait for the first one then the next one. Any time you're **not** waiting for one promise to settle before making another, the operations will be parallel. Therefore, if you store all promises in an array, that's already non-sequential. `Promise.all` just gives you the convenience to know when all are finished or not. – VLAZ Nov 06 '20 at 15:26

1 Answers1

1
await new Promise((r) => setTimeout(r, 500)) // add a small sleep delay

Don't do that.

You are guessing how long updateInkLevel will take


Just await the promise returned by updateInkLevel.

That will pause the loop until the promise resolves.


I was thinking of using Promise.all, but that would run each iteration in parallel, which is not I want here.

Are you sure you don't want them in parallel? That would often be more efficient.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • thanks for the reply. That's by design actually, updateInkLevel calls an external API. If I run everything too close together, it will overload that server. The sleep call, is meant to add some space between each call. – tinker Nov 06 '20 at 09:38
  • i don't really care how long updateInkLevel would take. But I do want to start next one as soon as possible. – tinker Nov 06 '20 at 09:38
  • 2
    @tinker — If you want to add space between calls then put a sleep function there **in addition** to waiting for the call to be resolved. – Quentin Nov 06 '20 at 09:39
  • 1
    @tinker If the server is that easily overloaded, I'd suggest having some protection/delay mechanism there as well. Otherwise, you're open to denial of service attacks if a malicious party decides to just fire a lot of calls. – VLAZ Nov 06 '20 at 09:41
  • @Quentin if I do that, the total running time is longer. We would be waiting for each call to complete fully before the next one can begin. – tinker Nov 06 '20 at 12:47
  • @vlaz good suggestion which I will definitely relay to then. But in the mean time I can't call in parallel. 2000 calls in parallel would lead to huge percentage of 500 response from the server. – tinker Nov 06 '20 at 12:49
  • @tinker — You explicitly said they shouldn't run in parallel! (And browsers have a limited number of HTTP requests they'll allow to go to any one given server at a time, so they'll get put in an internal queue anyway) – Quentin Nov 06 '20 at 13:09