Promises execution javascript

I am new to promises, so having little confusion in understanding why it’s giving output the way it is giving.

let p1= new Promise((resolve,reject)=>{
  resolve('foo');
})
let p2= new Promise((resolve,reject)=>{
  reject('bar');
})

console.log('bip')

p1.then(val=>{
  console.log(val)
  return p2
})
.then(
  console.log('baz')
)
.catch(err=>{
  console.log(err)
})
console.log('bop')

The output is

bip
baz
bop
foo
bar

I see console.log statements are getting printed before all promise statements but why is that. and why is the log statement printing ‘baz’ also getting printing first while being in .then statement?

Thanks for reading

This is from the MDN web docs for Promise.prototype.then():

“Once a Promise is fulfilled or rejected, the respective handler function ( onFulfilled or onRejected ) will be called asynchronously (scheduled in the current thread loop).”

This means that JS doesn’t stop and wait for your promise handler to run, it continues on as normal, and the handler will eventually be executed when its turn comes, but it has to wait for its turn in line in the event loop. So the console.log at the very bottom is executed before the console.log in the first then method because by the time JS gets to the handler for the first then statement waiting to be executed it has already executed the console.log at the bottom. Apparently the process of scheduling the handler takes enough time that it is placed in the event loop after the call to the console.log at the bottom. If you want ‘bop’ to be printed after ‘foo’ then you need to move the console.log at the bottom into the first then statement.

A traditional then statement looks something like (I’m leaving out the rejection handler because we all use catch now):

p.then(value => {
  // fulfillment
})

Look at your second then statement:

.then(
  console.log('baz')
)

It doesn’t look like the first one. You aren’t waiting for a value from the preceding then statement, you are just executing a console.log. I’m not 100% certain about this but my guess is that when JS gets to this statement, since it doesn’t have to wait for anything, it just executes it, which is why ‘baz’ is printed second. If you turned this into a more traditional then statement:

.then(() => {
  console.log('baz')
})

Then you’ll notice that the console.log statement never gets called because the preceding then returns p2 which is rejected and thus the second then is skipped because the rejection causes JS to skip to the catch.

I may not be 100% correct about all the details above but the bottom line is that when using promises you can’t rely on the order of statements in the code itself because promises are asynchronous, which means that there is no guarantee of when they will be resolved/rejected and thus when their handlers executed. If order of execution is important then you need to put the relevant statements inside the promise handlers.

Also, you can use async/await to guarantee order when using promises but that is a more advanced concept I won’t go into here.

3 Likes

@bbsmooth thank you for this insightful and detailed explanation.