Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript Promises: Executing Promises Sequentially

In an attempt to understand promises more clearly, i have been reading up a few very interesting articles on the same. I came across the following code which works perfectly for executing promises sequentially. But i am not able to understand how it works.

 function doFirstThing(){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(1);
       },1000)
   })
 }

 function doSecondThing(res){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(res + 1);
       },1000)
   })
 }

 function doThirdThing(res){
   return new Promise(function(resolve,reject){
       setTimeout(()=>{
           resolve(res + 2);
       },1000)
   })
 }
 promiseFactories = [doFirstThing, doSecondThing, doThirdThing];

 function executeSequentially(promiseFactories) {
         var result = Promise.resolve(); // this is the most problematic line 
               promiseFactories.forEach(function (promiseFactory) {
               result = result.then(promiseFactory);// what is happening here ?
    });
    return result;
 }

 executeSequentially(promiseFactories)

I do understand that promises are executed as soon as they are created. For some reason i am not able to understand the flow of execution. Especially this following line:

var result = Promise.resolve()//and empty promise is created.

Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?

result = result.then(promiseFactory);

I tried replacing the 'forEach' with a 'map' function and still yielded the same result. i.e, the methods where executed sequentially. Also, how is the value passed from one chained function to other ?

Any help or article/blog is highly appreciated.

like image 330
Nidhin Raj Avatar asked Jan 26 '23 13:01

Nidhin Raj


1 Answers

You can image a Promise as a box with execution inside. As far as the promise is created, the execution starts. To get the result value, you have to open the box. You can use then for it:

Promise.resolve(5).then(result => console.log(result)); // prints 5

If you want to chain promises you can do it by opening the box one by one:

Promise.resolve(5)
  .then(result => Promise.resolve(result + 1))
  .then(result => Promise.resolve(result * 2))
  .then(result => console.log(result));  // prints 12

This chaining makes the executions synchronous (one by one).

If you want to execute several promises asynchronously (you don't chain results), you can use Promise.all:

Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
  .then(result => console.log(result));  // prints [1,2,3]

In your case:

Promise.all(promiseFactories).then(result => console.log(result));

Another option how to work with promises is to await them:

(async ()=> {
   var res1 = await Promise.resolve(5);
   var res2 = await Promise.resolve(res1 + 1);
   var res3 = await Promise.resolve(res2 * 2);
   console.log(res3); // prints 12
})();

await works similar to then - it makes asynchronous execution to synchronous.

In your case:

async function executeSequentially(promiseFactories) {
    for (const p of promiseFactories) {
        const result = await p;
        console.log(result);
    } 
}

Note: await packs a value into a Promise out of the box:

var res1 = await 5; // same as await Promise.resolve(5)
like image 103
ttulka Avatar answered Feb 11 '23 11:02

ttulka