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