В какой очередности выполняются console.log, setTimeout и Promise в JavaScript
Что проверяют
Понимаете ли вы цикл событий и знаете ли, что микрозадачи выгребаются целиком.
Как отвечать
Порядок такой: сначала весь синхронный код, затем все микрозадачи, затем макрозадачи.
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// 1, 4, 3, 2Разбор:
console.log(1)синхронный, выполняется сразу;setTimeoutставит колбэк в очередь макрозадач;thenставит колбэк в очередь микрозадач;console.log(4)синхронный;- синхронный код кончился, движок опустошает очередь микрозадач, печатается 3;
- только теперь берётся макрозадача, печатается 2.
Правило движка: выполнить одну макрозадачу до конца, затем опустошить всю очередь микрозадач, и лишь потом взять следующую макрозадачу.
Что куда попадает: микрозадачи это колбэки промисов, продолжение после await, queueMicrotask, MutationObserver. Макрозадачи это таймеры, обработчики событий, сетевые колбэки.
Две тонкости, которые отличают полный ответ:
- микрозадача, добавленная из микрозадачи, выполнится в том же проходе, потому что очередь опустошается до конца. Отсюда бесконечная цепочка через
queueMicrotaskвешает страницу намертво, а черезsetTimeoutнет: браузер успевает отрисовать кадр; awaitэто синтаксис поверхthen, поэтому код после него это микрозадача, а не продолжение синхронного выполнения. Строка послеawaitпечатается позже, чем кажется при чтении сверху вниз.
В Node к этому добавляется process.nextTick со своей очередью, у которой приоритет выше промисов.
Где спотыкаются
Ставят setTimeout(fn, 0) раньше промиса.
Не знают, что очередь микрозадач опустошается целиком.
Считают код после await синхронным.
Путают приоритет process.nextTick и промисов в Node.