rb612
rb612

Reputation: 5563

Resolving an outer promise from another — alternating execution order?

I noticed some interesting behavior when resolving one promise from another:

const someTask = callback => {
  new Promise(res => res())
    .then(() => callback())
    .then(() => console.log("A 1!"))
    .then(() => console.log("A 2!"));
};

new Promise(res => someTask(res))
  .then(() => console.log("B 1!"))
  .then(() => console.log("B 2!"));

This outputs:

B 1!
A 1!
B 2!
A 2!

My thought would be that it would:

  1. At least enqueue one of the chains all at once so that all the A's .then callbacks would run first followed by B's, or vice versa, however they seem to alternate back and forth which is puzzling.

  2. Run A's first log statement before B, since it resolved before B.

I understand that this is both potentially implementation-dependent and that I shouldn't rely on execution order here (in my project I just care about A resolving B when it's done), but it intrigues me why this is happening. This is with native promises and Bluebird yields the same output.

Upvotes: 2

Views: 60

Answers (1)

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276306

I am going to avoid spec terminology like EnqoeueJob to not be more confusing

Whenever you .then(() => { ... }) that enqueues a microtask. Microtasks always run when there is only platform code remaining so "last" and always run before I/O.

In you case:

  • All promise constructors run synchronously - as they always do.
  • Your thens always run on a new microtick.

This means that in your case:

  1. First promise constructor runs synchronously calling someTask.
  2. someTask creates a promise and fulfills it synchronously.
  3. A microtick passes, the then is called which fulfills the original promise.
  4. Its then is scheduled and also the then of the original promise
  5. Those thens both schedule thens, which alternate

This is because microticks just schedule at the end of a microtask queue. So alternating is the "correct" behavior.

That is not implementation defined - although that was a coincidence and a mistake when building promises. You can but shouldn't rely on that order.

Upvotes: 1

Related Questions