1

Hi everyone I am new to promise as per documentation Promise runs parallel but I am not convinced for below example f1(), f2() function should execute parallel right and main function should have execution time same as the function who taken more time but why main function is taking more time then addition of both f1() and f2() it mean isn't it running sequentially

async function f1(){
    console.time("f1");
    for(i=0;i<100;i++){
        
    }
    console.timeEnd("f1");
}
async function f2(){
    console.time("f2");
    for(i=0;i<100;i++){
        
    }
    console.timeEnd("f2");
}
 async function main(){
    console.time("main");
   await Promise.all([f1(),f2()])
    console.timeEnd("main");
}
main();

output -
f1: 0.081ms
f2: 0.011ms
main: 2.858ms
Kurt
  • 678
  • 1
  • 7
  • 24
  • "*as per documentation Promise runs parallel*" - no, it doesn't. In which documentation did you read that? – Bergi Oct 01 '22 at 13:52

2 Answers2

0

Marking a function as async doesn't mean that the code within that function will run asynchronously. If your code doesn't use await or trigger any asynchronous calls, then your function will run entirely synchronously just as it would have without the async keyword. Instead, async means that your function can use await within the function (to wait for another Promise to resolve), and that your function will always return a Promise. The code you've written within f1 and f2 both use synchronous for loops, so both f1 and f2 run synchronously when called. To help with understanding, your code is more or less similar to doing (see code comments):

function f1(){ // note: No async
  console.time("f1");
  for(i=0;i<100;i++){}
  console.timeEnd("f1");
  return Promise.resolve(undefined); // returns a Promise that resolves immediately with `undefined`
}
function f2(){ // note, also not `async`
    console.time("f2");
    for(i=0;i<100;i++){}
    console.timeEnd("f2");
    return Promise.resolve(undefined);
}
async function main(){
  console.time("main");
  const p1 = f1(); // runs the for loop synchronously, returns a Promise which is stored in p1
  // only once the first `for` in `f1` is complete and the entire `f1` function has finished executing then does the below code execute
  const p2 = f2(); // runs the for loop synchronously, returns a Promise which is stored in p1
  await Promise.all([p1, p2]); // wait for both `p1` and `p2` to resolve (p1 and p2 have already resolved by this point)
  console.timeEnd("main");
}
main();

Another thing to note is that a Promise doesn't "run", it's more of an object that acts as a notification mechanism that tells your code once some sort of asynchronous operation has completed/failed. Promise.all() allows you to wait for multiple asynchronous operations which are occurring parallelly to complete before your code uses the values produced by the promises and continues with your code execution. For example (see code comments):

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); // setTimeout() triggers a timer that then triggers `resolve` once completed. `setTimeout()` is asynchronous.  
async function f1(){ // note: `async` because we `await` the Promise returned by `sleep()` below
  console.time("f1");
  await sleep(1000); // sleep for ~1s (await causes a pending Promise to be returned from `f1()`)
  console.timeEnd("f1");
}
async function f2(){ 
  console.time("f2");
  await sleep(1000); // sleeep for ~1s
  console.timeEnd("f2");
}
async function main(){
  console.time("main");
  const p1 = f1(); // runs f1() a stores the pending Promise in p1
  // while the asynchronous `setTimeout()` is running, we queue another call to `setTimeout()` below by calling `f2`
  const p2 = f2(); // runs `f2()` causing another setTimeout call to be queued and another pending Promise to be returned which is stored in `p2`
  // By this point we have two timeouts running in parallel in the background, `p1` will resolve once the first is complete and `p2` will resolve once the second is complete
  await Promise.all([p1, p2]); // wait for both pending promises, `p1` and `p2` to resolve (p1 and p2's setTimeout timers are running in the background and will resolve once completed)
  console.timeEnd("main");
}
main();

If you were to remove the Promise.all() and instead use:

async function main(){
  console.time("main");
  await p1();
  await p2();
  console.timeEnd("main");
}

Now your code will run sequentially, as p2() is only invoked once the Promise returned by calling p1() has resolved (as we're awaiting it with await). The Promise returned by p1() will only resolve once its associated setTimeout() call is completed.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • Thanks for answer i undertand this. so if i want run both function parellel what needs to be done? – Rakesh Kumar Sharma Oct 01 '22 at 07:53
  • 1
    @RakeshKumarSharma You can look into using [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) if you need to run synchronous code in the background off of the main thread. Usually, you won't need to do that as you can use typically use asynchronous tools to do what you need (eg: `setTimeout()`, `setInterval()`, etc.). – Nick Parsons Oct 01 '22 at 07:55
0

f1 and f2 are cpu bound which means they won't take advantage of concurrency and will in fact run synchronously.

Parallelism can only be achieved with concurrency when the tasks being called are I/O bound.

Few concepts worth brushing up:

fmagno
  • 1,446
  • 12
  • 27