18

How does this code work?

new Promise(resolve => {
    new Promise(resolve1 => {
        console.log(1)
        resolve1()
      })
      .then(() => {
        console.log(2)
      })
      .then(() => {
        console.log(3)
      })
    resolve()
  })
  .then(() => {
    console.log(4)
  })

The result is ‘1 2 4 3’

Eddie
  • 26,593
  • 6
  • 36
  • 58
yuqing-zhang
  • 203
  • 1
  • 4
  • 4
    What specifically has bothered you about it? What are you struggling with? – Jessica Aug 21 '20 at 09:25
  • "How does this code work?" - It doesn't. (You seem to mean "Why does it print 1, 2, 3, 4?", and it does not do that.) – Tomalak Aug 21 '20 at 09:30
  • check out promises and microtasks - i think its the best way to get an understanding ;) – Estradiaz Aug 21 '20 at 09:32
  • @Jessica because it should print 1234. Or if the main resolve isn't in the sequence of the other promises then, then why did it print 2 before 4, it should have been 1423 or 4123 or 1234, why is it kind of in series but not completely(1243 means the main resolve happened in between the two other`them` calls, why should it have been in between and not either after or before each?) – B''H Bi'ezras -- Boruch Hashem Aug 21 '20 at 09:33

6 Answers6

9

The easiest to understand what happens with Promises is to unchain it as much as you can.

So in this case, we have to remember that the Promise constructor is ran synchronously, microtasks are pushed to a queue (FIFO) and that it's only when the promise to which we attached our callback with .then() will resolve, that our callback will get pushed to that queue.

So we can rewrite your snippet like this:

const outer_1 = new Promise(resolve => {
  const inner_1 = new Promise(resolve1 => {
    console.log(1);
    resolve1();
  });
  const inner_2 = inner_1.then(() => {
    console.log(2);
  });
  const inner_3 = inner_2.then(() => {
    console.log(3);
  })
  resolve()
});
const outer_2 = outer_1.then(() => {
  console.log(4)
})
/*
And the execution order:

# sync
  inner_1 ->
    log(1)
    queue microtask (inner2)
  outer_1 ->
    queue microtask (outer2)
# microtask-checkpoint
  inner_2 -> 
    log(2)
    queue microtask (inner3)
  outer_2 ->
    log(4)
  inner_3 ->
    log(3)
*/
Kaiido
  • 123,334
  • 13
  • 219
  • 285
2

// Defining new promise 1
new Promise(resolve => {
    // Defining new promise 2
    new Promise(resolve1 => {
        // print 1
        console.log(1)
        // Resolve promise 1
        resolve1()
    })
        .then(() => {
            // After resolve 1 (then method), print 2
            console.log(2)
        })
        .then(() => {
            // Here we see chain of then methods, so after then 1
            // print 3. But keep in mind, that we also resolves
            // promise 1 before then of promise 2 actually happens,
            // so now JS doing it's own "parallel" tasks
            // (task/microtask pool, event loop)
            console.log(3)
        })
    // Resolve promise 1
    // BEFORE then from promise 2 completed
    resolve()
})
.then(() => {
    // This then method print 4
    console.log(4)
})

You can alter this code and make it async like that, by adding async/await

// Defining new promise 1
new Promise(async (resolve) => {
    // Defining new promise 2
    await new Promise(resolve1 => {
        // print 1
        console.log(1)
        // Resolve promise 1
        resolve1()
    })
        .then(() => {
            // After resolve 1 (then method), print 2
            console.log(2)
        })
        .then(() => {
            // chain then, prints 3 after first then
            console.log(3)
        })
    // Resolve promise 1
    // AFTER promise 2 complete its then
    resolve()
})
.then(() => {
    // This then method print 4
    console.log(4)
})
tarkh
  • 2,424
  • 1
  • 9
  • 12
2

First, top level code is executed: enter image description here

Through the execution, two functions are added to the microtask queue (red dots). Then, microtask queue is executed: enter image description here

One function is added to a microtask queue and then the function in the microtask queue is executed:

enter image description here

The End.

marzelin
  • 10,790
  • 2
  • 30
  • 49
1

They are two separate promises and will execute in parallel regardless of the order you put them in. If you're looking to get an order of 1, 2, 3, 4 you have to chain them properly or bring them together with Promise.all e.g.

let outerPromise, innerPromise;

outerPromise = new Promise(resolve => {
    innerPromise = new Promise(resolve1 => {
        console.log(1)
        resolve1()
      })
      .then(() => {
        console.log(2)

      })
      .then(() => {
        console.log(3)
      })
    resolve()
  })
  .then(() => {
    Promise.all([outerPromise, innerPromise]).then(() => console.log(4));
  });

Here is a good resource to read about promise chaining -> https://javascript.info/promise-chaining

Rei Mavronicolas
  • 1,387
  • 9
  • 12
0

Whenever "resolve ()" is called that completes the promise.

Also JavaScript function calls aren't blocking, meaning when you do .then on something, then another call afterwards, the second call will be executed first, then the first one. Similar idea with setTimeout etc

Here

    new Promise(resolve1 => {
        console.log(1)
        resolve1()
    })
        .then(() => {
            console.log(2)
        })
        .then(() => {
            console.log(3)
        })
    resolve()

You first declare a new Promise, which inherently doesn't console log anything (except 1)' the logging for that one only happens in the .then calls, which, as mentioned, are executed after (some) regular function call that follows then You are then following it with the main resolve, which prints 4. In the meantime, though, console.log takes time to operate, so even though the 2 was console logged, but it didn't have enough time to log 3 before 4, which is not dependant on waiting on the promise chain, was printed

Questions?

  • @yuqing-zhang check my update to comments, I did not see it in first time – tarkh Aug 21 '20 at 09:37
  • @tarkh it's still not correct you said "// Here we see chain of then methods, so after then 1 // print 3" which is not what happens, after then 1, 4 is printed, then 3, which is the main point of the question, why should the last written resolve happen in between the two thens s – B''H Bi'ezras -- Boruch Hashem Aug 21 '20 at 09:39
0

Because you're calling resolve() before the third .then() can be called.

It executes like this...

new Promise(resolve => {
    new Promise(resolve1 => { // okay. we're not waiting. let's keep moving
        console.log(1)
        resolve1(); // oh, yay! let's call .then()
      })
      .then(() => {
        console.log(2) // nothing was returned! let's call .then()
      })
      .then(() => {
        console.log(3) // nothing was returned! let's call .then()
      });
    // this is the next thing to be called after new Promise(resolve1 ...)
    // it will be called almost at the exact same time that resolve1() is called
    resolve(); oh, yay! let's call .then()
  })
  .then(() => {
    console.log(4)
  })
ihodonald
  • 745
  • 1
  • 12
  • 27