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