How to run each iteration of for or any loop parallely in Javascript

123 Views Asked by At

I am exploring async nature of js, and wish to write parallel execution for for each loop iteration. But Promise.all() execute sequentially right?, readed at a website. But I tried below implementation. Is it the correct way to achieve the same? like if Promise.all() is not executing promises parallely how each loop will run parallely. Thanks.

let asnycOpertions;// array to collect promises
for(let value of iterable) {
 asyncOperations.push(return new Promise((res,rej)=>{
  // someSynchronous operations
 }));
}
Promise.all(asyncOperations)
3

There are 3 best solutions below

0
T.J. Crowder On BEST ANSWER

You can't run JavaScript code in parallel without using a worker thread or similar. (Here I'm using "parallel" in the sense that two bits of code are literally executing at the same time; you can have interleaved code where two series of operations are taking place, each moving forward while the other waits, where they trade off who waits via promise completions.) Without a worker thread or similar, you can change when the synchronous JavaScript code runs, but you can't make it parallel with other JavaScript code in the same realm (loosely: the global environment and the things in it, like the environment for a window on browsers). Without a worker thread, you can have host-provided operations (like network requests) running in parallel, but not JavaScript code itself. The JavaScript specification requires that only a single thread be running code in the realm at any given time, so all JavaScript code in a single realm can be thought of as running on a single thread.

I am exploring async nature of js

The vast majority of JavaScript is synchronous. It's used in environments that have a lot of asynchronousness, but only async functions and promises cater to that specifically at the JavaScript language level.

and wish to write parallel execution for for each loop iteration

You can't, without worker threads. So if the code in the loop is synchronous (as you've suggested), you'll need workers to run it in parallel.

But Promise.all() execute sequentially right?, readed at a website.

That website is wrong or you misunderstood. Promise.all doesn't execute anything at all. It just observes promises. In the normal case, by the time you have a promise, the asynchronous work the promise will report on is already underway (or finished).¹ If that work is underway (such as network requests made via the host environment), that various pieces of work that the promises you pass into Promise.all will report on can be running in parallel.

Re your code:

let asnycOpertions;// array to collect promises
for(let value of iterable) {
 asyncOperations.push(return new Promise((res,rej)=>{
  // someSynchronous operations
 }));
}
Promise.all(asyncOperations)

The function you pass to new Promise (the promise executor function) is called synchronously during the new Promise call. Its job is to start the asynchronous operation by asking the host environment to do something asynchronous. That means the code you have for "someSynchronous operations" will run synchronously, exactly as though you didn't have new Promise there at all. Assuming that "someSynchronous operations" code calls resolve or reject at some stage, by the time you call Promise.all at the end, all of those promises are already settled, because that code ran synchronously.


¹ "already underway" - there are a small number of libraries that provide non-standard promises that don't start their work until you call then on the promise (explicitly, or implicitly via await). Thankfully these are rare. Standard promises in JavaScript do not behave that way.

0
Zibx On

Promise body is called synchronous. Asynchronous only means that inner async operations would not just wait outer i\o and stop other parts from running. So it is not multithreading, but can speed things up when you are working with fs and want to make bunch of requests to OS API, or make some AJAX calls.

let asnycOpertions;// array to collect promises
for(let value of iterable) {
 asyncOperations.push(new Promise((res,rej)=>{
  setImmediate(async ()=>{
    // do some async work
    res(resultOfWork);
  })
 }));
}
Promise.all(asyncOperations);
/* or you can use `await` to get results if your function is async:
   const results = await Promise.all(asyncOperations);
*/
5
Shahed On

As properly answered by T.J.Crowder, the Promise.all just stands as an observer to properly store the return value of each promise at its correct index and cancel everything if any one of the promise fails, and much other things but you can write code without using the Promise.all Another approach

// Assume you are uploading a dir
const folderData=[];
let results=[];
folderData.map(file=> 
uploadAPI(file).then(res=>results.push(res)).catch(err=>console.log(err)
)

// The catch is u may never have data of all uploads in results as soon as `js` 
// completes execution of `map`, but in this case i dont need all data , 
// because for every file upload i will show user that a
// file has uploaded like progress etc..

Regarding the async part all these api's request are not handled by JS itself, but these network request are handled by the OS API's and result provided back to program by OS which stores these results in the call stack to push whenever the main thread gets empty.

JS is the one who triggered/ invoked the request in the first place, but it has not triggered it parallely, it has triggered it sequentially, but it may appear as request triggered parallely, but it hasn't, but the invoked request are executed parallely, as OS API can handle multiple API request at once, and the result of those api's are also executed sequentially, so if we need to execute parallel code we have to use workers.