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?