Execution order question when processing JavaScript asynchronous functions (promise)

69 Views Asked by At

I'd like to know the order in which the JavaScript code below is executed and why. In particular, I would like to learn more about the contents of the code that goes into the microtask queue, focusing on step-by-step

var promise = Promise.resolve();

promise = promise.then(function(rtnVal) {
  console.log('1');
  var promise2 = Promise.resolve();
  promise2 = promise2.then(function(rtnVal) {
    console.log('2');
  });
  promise2 = promise2.then(function(rtnVal) {
    console.log('3');
  });
  console.log('4');
});

promise = promise.then(function(rtnVal) {
  console.log('5');
  var promise2 = Promise.resolve();
  promise2 = promise2.then(function(rtnVal) {
    console.log('6');
  });
  promise2 = promise2.then(function(rtnVal) {
    console.log('7');
  });
  console.log('8');
});

console.log('9');

Here's what I did: 9,1,4,2,5,8,3,6,7 ->I'm wondering why it runs in this order`

1

There are 1 best solutions below

9
trincot On BEST ANSWER

Some things to be aware of:

  • When a promise is resolved, any then callbacks (if any) are put on the PromiseJob queue
  • When then() is called (not its callback), the returned promise is always pending, even if that then() call is made on a resolved promise. This is because the returned promise can only be resolved by executing the callback that is given to the then method since it determines how the promise will resolve, but which can only execute asynchronously.

To ease the analysis, I modified your script to give a name to each promise (a to i) and to each callback function (a_then, ...), but the logic and output remains the same:

var a = Promise.resolve();

var b = a.then(function a_then() {
  console.log(1);
  var c = Promise.resolve();
  var d = c.then(function c_then() {
    console.log(2);
  });
  var e = d.then(function d_then() {
    console.log(3);
  });
  console.log(4);
});

var f = b.then(function b_then() {
  console.log(5);
  var g = Promise.resolve();
  var h = g.then(function g_then() {
    console.log(6);
  });
  var i = h.then(function h_then() {
    console.log(7);
  });
  console.log(8);
});

console.log(9); 

Here is a sequence of events that happen during the execution of that code.

  • The first column represents what is executing (the main script, a function initiated from the event loop, or the host that dequeues an item from the PromiseJob queue)
  • The second column has the current expression/statement being evaluated
  • The columns a to i represent the state of the promise with that name: ? for pending, F for fulfilled.
  • The last column pictures what is present in the PromiseJob queue, managed by the host

Here we go:

Task Action a b c d e f g h i PromiseJob queue
Script a = Promise.resolve() F - - - - - - - -
Script b = a.then(a_then) F ? - - - - - - - a_then
Script f = b.then(b_then) F ? - - - ? - - - a_then
Script console.log(9) F ? - - - ? - - - a_then
Host dequeue a_then F ? - - - ? - - -
a_then console.log(1) F ? - - - ? - - -
a_then c = Promise.resolve() F ? F - - ? - - -
a_then d = c.then(c_then) F ? F ? - ? - - - c_then
a_then e = d.then(d_then) F ? F ? ? ? - - - c_then
a_then console.log(4) F ? F ? ? ? - - - c_then
a_then return resolves b F F F ? ? ? - - - c_then, b_then
Host dequeue c_then F F F ? ? ? - - - b_then
c_then console.log(2) F F F ? ? ? - - - b_then
c_then return resolves d F F F F ? ? - - - b_then, d_then
Host dequeue b_then F F F F ? ? - - - d_then
b_then console.log(5) F F F F ? ? - - - d_then
b_then g = Promise.resolve() F F F F ? ? F - - d_then
b_then h = g.then(g_then) F F F F ? ? F ? - d_then, g_then
b_then i = h.then(h_then) F F F F ? ? F ? ? d_then, g_then
b_then console.log(8) F F F F ? ? F ? ? d_then, g_then
b_then return resolves f F F F F ? F F ? ? d_then, g_then
Host dequeue d_then F F F F ? F F ? ? g_then
d_then console.log(3) F F F F ? F F ? ? g_then
d_then return resolves e F F F F F F F ? ? g_then
Host dequeue g_then F F F F F F F ? ?
g_then console.log(6) F F F F F F F ? ?
g_then return resolves h F F F F F F F F ? h.then
Host dequeue h_then F F F F F F F F ?
h_then console.log(7) F F F F F F F F ?
h_then return resolves i F F F F F F F F F
Host queue is empty F F F F F F F F F