Search code examples
javascriptes6-promise

Why are two promises not executed in sequence?


I would like to show 2 cases and ask only about the second case.

Case1:

Promise.resolve(1)
  .then((x) => console.log(1))
  .catch((x) => console.log(2))
  .then((x) => console.log(3));

Promise.reject(2)
  .then((x) => console.log(4))
  .then((x) => console.log(5))
  .catch((x) => console.log(6))
  .then((x) => console.log(7));

// 1 3 6 7

Its ok. this code produced the following sequence: 1 3 6 7

Case 2:

Promise.resolve(1)
  .then((x) => console.log(1))
  .catch((x) => console.log(2))
  .then((x) => console.log(3));

Promise.reject(2)
  .then((x) => console.log(4))
  // .then((x) => console.log(5))
  .catch((x) => console.log(6))
  .then((x) => console.log(7));

// 1 6 3 7

This code produced the strange sequence: 1 6 3 7

Please tell me about the mechanism that temporarily stops the execution of the first promise.


Solution

  • Let's analyse the second snippet and give some names to the promises that are created:

    Promise.resolve(1)  // promise A
      .then((x) => console.log(1)) // B
      .catch((x) => console.log(2)) // C
      .then((x) => console.log(3)); // D
    
    Promise.reject(2) // E
      .then((x) => console.log(4)) // F
      .catch((x) => console.log(6)) // G
      .then((x) => console.log(7)); // H
    

    First the main, synchronous script executes as follows:

    • Create A as fulfilled promise
    • Create B as pending promise. As it chains to a resolved promise:
      • Queue the job to execute (x) => console.log(1) and resolve B
    • Create C as pending promise
    • Create D as pending promise
    • Create E as rejected promise
    • Create F as pending promise. As it chains to a rejected promise:
      • Queue the job to reject F -- no custom callback
    • Create G as pending promise
    • Create H as pending promise

    At this moment the synchronous part ends: the callstack is empty. The engine will now process any jobs that might be waiting in its queues. The promise job queue has two entries, so execution will continue as follows:

    The first job is pulled from the promise job queue and is executed in a first microtask:

    • Execute (x) => console.log(1) and resolve B
      • Queue the job to resolve C -- no custom callback

    The next job is pulled from the promise job queue and is executed:

    • Reject F
      • Queue the job to execute (x) => console.log(6) and resolve G

    The next job is pulled from the promise job queue and is executed:

    • Resolve C
      • Queue the job to execute (x) => console.log(3) and resolve D

    The next job is pulled from the promise job queue and is executed:

    • Execute (x) => console.log(6) and resolve G
      • Queue the job to execute (x) => console.log(7) and resolve H

    The next job is pulled from the promise job queue and is executed:

    • Execute (x) => console.log(3) and resolve D

    The next job is pulled from the promise job queue and is executed:

    • Execute (x) => console.log(7) and resolve H

    The promise job queue is now empty and the task ends.

    And so it is expected that the output is 1, 6, 3, 7