Почему именно такой порядок вывода в консоль
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 шт):
На создание объекта в JavaScript требуется время, в частности у вас таким объектом является Promise, который создается при возврате из первого промиса. За это время успевают проскочить 4 и 5. Потом выполняется 2, в том промисе, который создан. Ну и когда все промисы разрезолвили себя, то остаётся распечатать то, что осталось в цепочке.
Судя по всему, обработка резолва промиса (который вернули в then) занимает 2 микротаска, потому поэтапно очередь формируется так:
- С1, С3 (эти два - после синхронного кода)
- х, С4 (эти добавляются и обрабатываются после предыдущих двух)
- y, С5
- С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"