queueMicrotask() нужен, чтобы поставить функцию в очередь микрозадач. Такая функция выполнится не сразу в той же строке, а после завершения текущего синхронного кода, но раньше обычных таймеров вроде setTimeout().
Это полезный инструмент, когда нужно отложить небольшой кусок логики на самый ближайший момент после текущего выполнения: синхронизировать состояние, выровнять порядок вызовов или аккуратно завершить текущий шаг работы, не уходя в более позднюю очередь макрозадач.
Синтаксис
Базовая запись выглядит так:
queueMicrotask(callback)
Где:
callback- функция, которую нужно поставить в очередь микрозадач
Простейший пример:
queueMicrotask(() => {
console.log("Микрозадача выполнена");
});
Что принимает queueMicrotask()
queueMicrotask() принимает одну функцию.
queueMicrotask(() => {
console.log("run");
});
В отличие от setTimeout(), здесь нет задержки в миллисекундах и нет дополнительных аргументов для передачи в колбэк. Если нужно передать значения, обычно используют замыкание.
const userName = "Анна";
queueMicrotask(() => {
console.log(userName);
});
Что возвращает queueMicrotask()
queueMicrotask() ничего полезного не возвращает.
const result = queueMicrotask(() => {
console.log("run");
});
console.log(result); // undefined
Главный эффект здесь не в возвращаемом значении, а в том, что функция попадает в очередь микрозадач.
Простой пример
console.log("start");
queueMicrotask(() => {
console.log("microtask");
});
console.log("end");
Результат будет таким:
start
end
microtask
Это показывает главное поведение метода: колбэк не выполняется мгновенно, но и не откладывается так далеко, как обычный таймер.
queueMicrotask() выполняется после текущего синхронного кода
Это базовое правило.
console.log("A");
queueMicrotask(() => {
console.log("B");
});
console.log("C");
Результат:
A
C
B
Сначала JavaScript доходит до конца текущего синхронного блока, и только потом начинает выполнять микрозадачи.
Микрозадача выполняется раньше setTimeout(..., 0)
Это один из самых важных практических нюансов.
console.log("start");
queueMicrotask(() => {
console.log("microtask");
});
setTimeout(() => {
console.log("timeout");
}, 0);
console.log("end");
Результат будет таким:
start
end
microtask
timeout
Хотя setTimeout(..., 0) тоже откладывает выполнение совсем ненадолго, микрозадача всё равно выполнится раньше.
Несколько queueMicrotask() выполняются в порядке добавления
Это тоже полезно понимать точно.
queueMicrotask(() => {
console.log("microtask 1");
});
queueMicrotask(() => {
console.log("microtask 2");
});
Результат:
microtask 1
microtask 2
Если вы ставите несколько микрозадач подряд, они выполняются по очереди.
Микрозадача может поставить в очередь ещё одну микрозадачу
И она тоже выполнится до перехода к таймерам.
queueMicrotask(() => {
console.log("first");
queueMicrotask(() => {
console.log("second");
});
});
setTimeout(() => {
console.log("timeout");
}, 0);
Результат:
first
second
timeout
Это полезная возможность, но с ней важно быть аккуратным: если бесконечно добавлять новые микрозадачи из микрозадач, можно надолго задержать таймеры, рендеринг и остальную работу цикла событий.
queueMicrotask() не ставит код на паузу
Это важно понимать правильно.
queueMicrotask() ничего не ждёт и не блокирует. Он только планирует выполнение функции на ближайший момент после завершения текущего синхронного кода.
console.log("A");
queueMicrotask(() => {
console.log("B");
});
console.log("C");
Синхронная часть продолжает выполняться сразу. Метод не делает паузу и не останавливает программу.
Чем queueMicrotask() отличается от Promise.resolve().then()
Эти подходы похожи по моменту выполнения, но это не одно и то же.
queueMicrotask(() => {
console.log("microtask");
});
Promise.resolve().then(() => {
console.log("promise");
});
Оба колбэка попадают в очередь микрозадач и выполняются очень рано. Но есть отличия:
queueMicrotask()явно ставит функцию в очередь микрозадачPromise.resolve().then()делает это через промисqueueMicrotask()не создаёт новый промис- ошибка внутри
queueMicrotask()ведёт себя как обычное необработанное исключение - ошибка внутри
then()приводит к отклонённому промису и может статьunhandledRejection
Для простой постановки микрозадачи queueMicrotask() обычно выглядит прямее и понятнее.
Чем queueMicrotask() отличается от setTimeout()
Это сравнение особенно полезно запомнить.
queueMicrotask()ставит колбэк в очередь микрозадачsetTimeout()ставит колбэк в очередь таймеров- микрозадача выполняется раньше таймера
setTimeout()умеет откладывать выполнение на миллисекунды, аqueueMicrotask()нет
Пример:
queueMicrotask(() => {
console.log("microtask");
});
setTimeout(() => {
console.log("timeout");
}, 0);
Здесь сначала сработает microtask, а потом timeout.
Когда это полезно
queueMicrotask() особенно удобен, когда:
- нужно выполнить код сразу после текущего синхронного шага
- нужно выровнять порядок выполнения без таймера
- нужно отложить небольшую служебную логику на ближайший момент
- нужно синхронизировать одинаковое поведение между синхронными и асинхронными ветками
- важно выполнить код раньше, чем сработают обычные таймеры
Пример:
function notify(value) {
queueMicrotask(() => {
console.log("Обновлённое значение:", value);
});
}
console.log("start");
notify(42);
console.log("end");
Результат будет таким:
start
end
Обновлённое значение: 42
Частые ошибки
Думать, что queueMicrotask() выполняет код сразу
console.log("start");
queueMicrotask(() => {
console.log("run");
});
console.log("end");
Сначала завершится текущий синхронный код, и только потом выполнится микрозадача.
Путать queueMicrotask() и setTimeout(..., 0)
queueMicrotask(() => {
console.log("microtask");
});
setTimeout(() => {
console.log("timeout");
}, 0);
Это не одно и то же. Микрозадача выполнится раньше таймера.
Вызывать функцию сразу вместо передачи функции
queueMicrotask(console.log("Привет"));
Здесь console.log("Привет") выполнится немедленно, а в queueMicrotask() попадёт уже не та функция, которую вы ожидали передать.
Правильно так:
queueMicrotask(() => {
console.log("Привет");
});
Думать, что queueMicrotask() возвращает промис
const result = queueMicrotask(() => {
console.log("run");
});
queueMicrotask() не возвращает Promise. У него другая задача: просто поставить функцию в очередь микрозадач.
Перегружать очередь микрозадач
function repeat() {
queueMicrotask(repeat);
}
repeat();
Такой код может надолго занять цикл событий и помешать таймерам, рендерингу и другой работе. Для тяжёлых или бесконечных повторов queueMicrotask() подходит плохо.
Быстрая памятка
queueMicrotask()ставит функцию в очередь микрозадач- колбэк выполняется после текущего синхронного кода
- микрозадача выполняется раньше
setTimeout(..., 0) - метод принимает только функцию
- задержку в миллисекундах указать нельзя
- метод ничего полезного не возвращает
- несколько микрозадач выполняются в порядке добавления
- слишком большое количество микрозадач может задерживать остальную работу цикла событий
Коротко
queueMicrotask() в JavaScript нужен, чтобы поставить функцию в очередь микрозадач. Главное, что стоит запомнить: колбэк выполняется не сразу, а после текущего синхронного кода, при этом раньше таймеров вроде setTimeout(..., 0), метод не возвращает промис и особенно полезен там, где нужно очень быстро отложить небольшой кусок логики без перехода в более позднюю очередь задач.