0

I have a loop that calls several sync functions simultaneously and in parallel. When they are all done, a series of final operations must be called to end the program.

For example, look at this simple code:

(async () => { var items = [1, 2, 3, 4, 5]; for (var item of items) { console.log('Running... #' + item); var loop = async function(item) { var delay = getRandom(3, 7)*1000; await sleep(delay); console.log('Done. #' + item + ' with delay: ' + delay); } loop(item); } //while (true) {await sleep(1000);} console.log('Finish'); })(); /////////////////////////////////////// async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function getRandom(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1) + min); } 

The output is as follows:

Running... #1 Running... #2 Running... #3 Running... #4 Running... #5 Finish Done. #5 with delay: 3000 Done. #2 with delay: 4000 Done. #4 with delay: 6000 Done. #1 with delay: 7000 Done. #3 with delay: 7000 

Which is not good, because "Finish" is printed before the end of all the loops.
Note that "Finish" is an example, and here I may have final operations such as closing a database or browser, and so on.

If I call the functions like this:

await loop(item); 

Result:

Running... #1 Done. #1 with delay: 3000 Running... #2 Done. #2 with delay: 7000 Running... #3 Done. #3 with delay: 6000 Running... #4 Done. #4 with delay: 6000 Running... #5 Done. #5 with delay: 5000 Finish 

The phrase "Finish" is printed well at the end, but instead all my functions are executed async and in order, which is not desirable.

Another way I tried is to use an infinite While similar to the one I commented on in the source code:

while (true) {await sleep(1000);} 

Result:

Running... #1 Running... #2 Running... #3 Running... #4 Running... #5 Done. #1 with delay: 3000 Done. #5 with delay: 4000 Done. #3 with delay: 6000 Done. #4 with delay: 6000 Done. #2 with delay: 7000 

The operation is correct here, but it never reaches "Finish".

Another way I thought of was to put a counter at the end of the functions and put a condition inside the end loop to control it and exit the loop.

like this:

(async () => { var items = [1, 2, 3, 4, 5]; var n = 0; // <==== for (var item of items) { console.log('Running... #' + item); var loop = async function(item) { var delay = getRandom(3, 7)*1000; await sleep(delay); console.log('Done. #' + item + ' with delay: ' + delay); n++; // <==== } loop(item); } while (true) { await sleep(1000); if (n == items.length) break; // <==== } console.log('Finish'); })(); 

And its output:

Running... #1 Running... #2 Running... #3 Running... #4 Running... #5 Done. #2 with delay: 3000 Done. #1 with delay: 4000 Done. #5 with delay: 4000 Done. #3 with delay: 5000 Done. #4 with delay: 6000 Finish 

This is my expected and desired output. But I think the solution is not clean! Because the counter is difficult to control in the program, and maybe in some places I needed to return from the function and I should always be careful to increase n by one.

So I think there should be a simpler and more principled solution to achieve this goal. Maybe, for example, putting all the call results in an array and checking it in While, but as much as possible I do not want to change the structure of my program, and it is better to add everything simply and at the end of the code.

Do you have a solution?

2
  • 1
    See the linked question's answers. Short version: await Promise.all(items.map(async (item) => { /*...code using `await`...*/ })); Commented Apr 26, 2022 at 13:07
  • 1
    Consider Promise.all. Check stackoverflow.com/questions/45285129/… Commented Apr 26, 2022 at 13:08

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.