📜 ⬆️ ⬇️

How to work with async / await in JavaScript cycles

How to run asynchronous loops in order or in parallel in JavaScript?


Before doing asynchronous magic, I want to remind you of the classic synchronous loops.


Synchronous loops


A long time ago I wrote cycles in this way (maybe you too):


for (var i=0; i < array.length; i++) { var item = array[i]; //  -  item } 

This cycle is good and fast. But he has a lot of problems with readability and support. After a while, I got used to his better version:


 array.forEach((item) => { //  -  item }); 

JavaScript language is developing very quickly. There are new features and syntax. One of my favorite improvements is async / await .


Now I use this syntax quite often. And sometimes there are situations when I need to do something with the elements of the array asynchronously.


Asynchronous loops


How to use await in a loop body? Let's just try to write an asynchronous function and wait for the task of processing each element:


 async function processArray(array) { array.forEach(item => { //       //     ! await func(item); }) } 

This code will generate an error. Why? Because we cannot use await inside a synchronous function. As you can see, processArray is an asynchronous function. But the anonymous function that we use for forEach is synchronous .


What can you do about it?


1. Do not wait for the execution result


We can define an anonymous function as asynchronous:


 async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); } 

But forEach will not wait for the task to complete. forEach is a synchronous operation. It will simply start the task and go on. Check on a simple test:


 function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) { //    await  Promise //    delay await delay(); console.log(item); } async function processArray(array) { array.forEach(async (item) => { await delayedLog(item); }) console.log('Done!'); } processArray([1, 2, 3]); 

In the console we will see:


 Done! 1 2 3 

In some situations this may be a normal result. But still, in most variants, this is not the appropriate logic.


2. Processing the loop sequentially


To wait for the result of the execution of the loop body, we need to return to the good old "for" loop. But this time we will use its new version with the for..of construction (thanks to Iteration Protocol ):


 async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); } 

This will give us the expected result:


 1 2 3 Done! 

Each array element will be processed sequentially. But we can start the cycle in parallel!


3. Cycle processing in parallel


You need to slightly change the code to start operations in parallel:


 async function processArray(array) { //  "map"    const promises = array.map(delayedLog); //       await Promise.all(promises); console.log('Done!'); } 

This code can run several delayLog tasks in parallel. But be careful with large arrays. Too many tasks may be too hard for the CPU and memory.


Also, please do not confuse the "parallel tasks" from the example with real parallelism and threads. This code does not guarantee parallel execution. Everything depends on the loop body (in the example, this is delayedLog ). Network requests, webworkers and some other tasks can be executed in parallel.


')

Source: https://habr.com/ru/post/435084/


All Articles