Почему именно такой порядок вывода в консоль

new Promise((resolve) => resolve()) // P1
  .then(() => { // C1
    console.log(1);
    return new Promise((resolve) => resolve());
  })
  .then(() => console.log(2)); // C2

new Promise((resolve) => resolve()) // P2
  .then(() => console.log(3)) // C3
  .then(() => console.log(4)) // C4
  .then(() => console.log(5)) // C5
  .then(() => console.log(6)); // C6

Ответ: 1, 3, 4, 5, 2, 6.

Почему 4, 5 успевают проскочить, а 6 нет? Я понимаю, что когда из then возвращается промис, создаётся микразадача чтоб его обработать, но не понимаю, почему вообще успевают проскочить в консоль 4, 5 перед 2. Для удобства обсуждения, в комментариях к коду написал краткие аббревиатуры.


Ответы (2 шт):

Автор решения: Roman C

На создание объекта в JavaScript требуется время, в частности у вас таким объектом является Promise, который создается при возврате из первого промиса. За это время успевают проскочить 4 и 5. Потом выполняется 2, в том промисе, который создан. Ну и когда все промисы разрезолвили себя, то остаётся распечатать то, что осталось в цепочке.

→ Ссылка
Автор решения: Alexandroppolus

Судя по всему, обработка резолва промиса (который вернули в then) занимает 2 микротаска, потому поэтапно очередь формируется так:

  1. С1, С3 (эти два - после синхронного кода)
  2. х, С4 (эти добавляются и обрабатываются после предыдущих двух)
  3. y, С5
  4. С2, С6

Т.е. если бы микрозадачи "х" и "у" что-то вываливали в консоль, то как раз и вышло бы:

1, 3, х, 4, у, 5, 2, 6.

И вопрос тут - почему этих вспомогательных действий было два, а не одно (т.е. почему с5 пролезла перед с2, по поводу с4 вопросов нет).

Покурил MDN, и вот что получается. Рассмотрим более простой пример, принципиально не отличающийся от твоего:

var promise = Promise.resolve();

new Promise((resolve) => resolve(promise))
  .then(() => console.log(1));

promise
  .then(() => console.log(2))
  .then(() => console.log(3));

Печатает 2 3 1, на resolve(promise) уходит те же два микротаска.

Если resolve(promise) заменить на promise.then(resolve), то будет 2 1 3, т.е. на один микротаск меньше.

MDN указывает, что вызов resolve(promise) - то же самое, как вызов promise.then(resolve) в микротаске, т.е. как queueMicrotask(() => promise.then(resolve)), поэтому получаются те самые 2 микротаска.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise "The resolve function"

→ Ссылка