Куда пойдет выполнение после запуска промиса в JavaScript
Что проверяют
Знаете ли вы, что executor промиса выполняется синхронно, а обработчики .then попадают в очередь микрозадач. Обычно дают код с console.log, setTimeout и промисами и просят назвать порядок вывода.
Как отвечать
Разложите по шагам:
- executor синхронен: функция, переданная в
new Promise(...), вызывается сразу, в том же стеке. Промисы «жадные»: отдельно их запускать не нужно, и отдельного потока они не создают; - код после создания промиса продолжает выполняться синхронно до конца текущей задачи;
- обработчики
.then,.catch,.finallyставятся в очередь микрозадач, когда промис переходит вfulfilledилиrejected. Если промис уже выполнен к моменту вызова.then, обработчик встаёт в очередь сразу, но всё равно не выполняется синхронно; - микрозадачи выполняются, когда стек вызовов опустел, все подряд, до следующей макрозадачи (
setTimeout, события, сетевые колбэки) и до отрисовки; awaitработает так же: код async-функции до первогоawaitсинхронен, остаток функции продолжится микрозадачей.
Короткий пример, который стоит уметь разобрать вслух:
console.log(1);
setTimeout(() => console.log(5));
new Promise((resolve) => { console.log(2); resolve(); })
.then(() => console.log(4));
console.log(3);Вывод 1 2 3 4 5: executor синхронный, then это микрозадача, setTimeout это макрозадача и идёт последним.
Если сам executor ждёт setTimeout или fetch, resolve вызовется позже, в колбэке той макрозадачи, и только тогда then попадёт в очередь.
Где спотыкаются
Считают, что тело new Promise выполняется асинхронно, и ставят 2 после 3. Это самая частая ошибка в таких задачах.
Думают, что setTimeout(fn, 0) сработает раньше then, раз задержка нулевая. Микрозадачи всегда выбираются раньше следующей макрозадачи.
Связывают промисы с многопоточностью. Ваш JavaScript выполняется в одном потоке, промис только откладывает колбэк, а бесконечная цепочка микрозадач заблокирует и отрисовку, и клики.