skip to Main Content

What happens when I return a promise from a .then method which is wrapped in another object like:

somepromise
.then((step1Result) => {
  return {
    'val1' : synchronousCalculation(),
    'val2' : asyncCalculation() // << THIS HERE
  };
})
.then((result) => {
  // PATH2
});

i.e. is PATH2 guaranteed to have a settled promise in result['val2']?

A simpler situation is always guaranteed as mentioned in this question where the top answer mentions this article:

When you return something from a then() callback, it’s a bit magic. If you return a value, the next then() is called with that value. However, if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails)

Note that I’m avoiding to call await asyncCalculation() because I cannot turn the whole method into async, there’s too much that would have to change if I did that.

3

Answers


  1. What happens when I return a promise from a .then method which is wrapped in another object

    The same thing as with any other value of a property of that object, it is not treated in any special way.

    i.e. is PATH2 guaranteed to have a settled promise in result[‘val2’]?

    No, there is no guarantee about that, result['val2'] holds a promise that could be in any state.

    What you could do is something like this:

    function synchronousCalculation() {
      return 1
    }
    
    function asyncCalculation() {
      return Promise.resolve(2)
    }
    
    
    Promise.resolve(0)
    .then((step1Result) => {
      return Promise.all([
        synchronousCalculation(),
        asyncCalculation()
      ]);
    })
    .then(([val1, val2]) => {
      console.dir(val1)
      console.dir(val2)
    });

    like that:

    Login or Signup to reply.
  2. No, the Promise is not guaranteed to be resolved. Supposing that synchronousCalculation and asyncCalculation both take step1Result as the only argument, you could refactor your code like this:

    const synchronousCalculationResult = somepromise.then(synchronousCalculation);
    const asyncCalculationResult = somepromise.then(asyncCalculation);
    
    const fullResult = Promise.all([
      synchronousCalculationResult,
      asyncCalculationResult,
    ]).then(([val1, val2]) => ({
      val1,
      val2,
    }));
    
    Login or Signup to reply.
  3. When Promise.then( callback )‘s callback returns a Promise itself, the next chained then will await that promise. So in order to be sure all your values are resolved, you would need to turn your callback async itself.

    somepromise
    .then(async step1Result => {
    
      const result = {
        'val1' : synchronousCalculation(),
        'val2' : await asyncCalculation()
      };
    
      return result;
    
    })
    .then(result => {
      // This `then` now resolves to the object
      // PATH2
    });
    

    An async function basically returns a Promise that resolves whenever all await statements have been resolved. And returning Promises inside then will chain them together. Consider this example:

    async function delay( d ){
    
      console.log( `Delaying by ${d}ms` );
        
      return new Promise(r => setTimeout(r, d));
      
    }
    
    delay( 1000 )
      .then(() => delay( 1000 ))
      .then(() => delay( 1000 ))
      .then(() => {
      
        console.log( `Delayed by 3000ms, because all promises chain` );
      
      });

    You can see that after resolving the first one, the then from that promise gets called. But then does not return the same promise:

    async function delay( d ){
    
      console.log( `Delaying by ${d}ms` );
        
      return new Promise(r => setTimeout(r, d));
      
    }
    
    const step1 = delay( 1000 );
    const step2 = step1.then(() => delay( 1000 ));
    const step3 = step2.then(() => delay( 1000 ));
    
    step3.then(() => {
       
       console.log( step1 === step2 ); // False
       console.log( step2 === step3 ); // False
       console.log( `Every time a new promise got made!` );
      
     });

    Every time a new Promise is returned than get’s awaited. So internally, you can nest as many promises as you want. If a Promise is returned, the next step in the chain will await it being resolved, if a value is returned, the next step just gets executed with that value.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search