Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Sunil Mendu
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Sunil Mendu

The ES6 Promise Constructor And Its Executor Function Are Invoked Synchronously

By Ben Nadel on

This is primarily a note-to-self; but, I just wanted to codify the fact that the ES6 Promise construtor - and the executor function that you pass to it - are invoked synchronously in your code. The only reason that this is worth mentioning at all is because everything else about Promises are asynchronous. So, it's not entirely obvious that your executor function wouldn't also be invoked asynchronously. But, the fact that it is synchronous means that you can make strong assertions about the order of operations in your control flow.

To see this in action, all we have to do is log some messages around the Promise constructor and the invocation of our executor function:

  • console.log( "Start." );
  •  
  • // Check to see that Promise constructor is executed synchronously.
  • var promise = new Promise(
  • function( resolve, reject ) {
  •  
  • console.log( "In Promise constructor." );
  •  
  • resolve( "Future value." );
  •  
  • }
  • );
  •  
  • // Check to see that Promise resolution handlers are invoked asynchronously.
  • promise.then(
  • function( result ) {
  •  
  • console.log( "Promise resolution:", result );
  •  
  • }
  • );
  •  
  • console.log( "End." );

As you can see, we're logging messages to the console in and around the Promise constructor. And, when we run this code in Node.js, we get the following output:


 
 
 

 
 The promise constructor and its executor function are invoked synchronously. 
 
 
 

As you can see, the log statement in our Promise constructor and executor function is invoked synchronously, falling in between the "Start" and "End" log statements. And, of course, our Promise resolution handler is invoked asynchronously as we expect it to be.

This may seem like an unnecessary investigation; but, having a solid mental model for Promise execution is an important part of understanding control flow in JavaScript and Node.js. It means that we can make strong assertions about the order of operations in our code; and, most importantly, about possible race conditions in the JavaScript event loop.



Reader Comments

@Ben,

Good link - Nolan is the man. I've been really digging the PouchDB library this year -- hoping to build an offline-first app with it (when I can be better about actually concentrating).

Thanks for clarifying the solid mental model, I think that's the primary difference between promises and observables (RxJS).

BTW, I really to read your code, can you please share linting configuration you have set up?

@Rumen,

I appreciate your comment - but I don't have a linter :D This is just the way I normally code. And, I'm thrilled that you like it - many people really do not like the way that I format my code. Much thanks!

Probably best to point out that the resolve() is actually happening synchronously along with everything else, it's the then() that receives it, that is being handled outside of the main execution.

@Blade,

Ah, interesting. I am not sure how reduce is implemented under-the-covers; but, to be sure, all function invocations are always synchronous (though they may lead to asynchronous behavior, as you are saying, with the subsequent .then() call).