0Pricing
JavaScript Academy · Урок

Микрозадачи и промисы

Узнайте, почему обратные вызовы промисов выполняются первыми.

«Микрозадачи и промисы» — бесплатный урок JavaScript Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения JavaScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс JavaScript Academy содержит 4 уроков всего.

Что такое микрозадача?

Микрозадача — это отложенная задача с высоким приоритетом. Обратные вызовы промисов (.then, .catch, .finally) и queueMicrotask ставят микрозадачи в очередь.

Главное правило: после каждого синхронного выполнения все микрозадачи обрабатываются до любой макрозадачи.

Обратные вызовы промисов выполняются отложенно

Даже уже разрешённый промис ставит свой обратный вызов .then в очередь микрозадач. Он не выполняется синхронно.

console.log('start');
Promise.resolve().then(() => console.log('promise then'));
console.log('end');

Микрозадачи опережают макрозадачи

Это самое важное правило порядка выполнения. Обратный вызов промиса выполняется до обратного вызова setTimeout, даже если таймер был поставлен в очередь первым.

setTimeout(() => console.log('timeout (macro)'), 0);
Promise.resolve().then(() => console.log('promise (micro)'));
console.log('sync');

Очередь микрозадач обрабатывается полностью

Цикл обработки событий опустошает всю очередь микрозадач, прежде чем перейти к следующей макрозадаче. Несколько обратных вызовов промисов выполняются подряд в рамках этой обработки.

setTimeout(() => console.log('macro'), 0);
Promise.resolve().then(() => console.log('micro 1'));
Promise.resolve().then(() => console.log('micro 2'));
console.log('sync');

Цепочки промисов

Каждый .then в цепочке ставит новую микрозадачу в очередь, когда предыдущая задача завершается. При этом все они выполняются до любого ожидающего таймера.

setTimeout(() => console.log('timeout'), 0);
Promise.resolve()
  .then(() => console.log('then 1'))
  .then(() => console.log('then 2'))
  .then(() => console.log('then 3'));
console.log('sync');

Микрозадачи, поставленные во время обработки очереди

Если микрозадача ставит в очередь другую микрозадачу, новая микрозадача также выполняется в рамках той же обработки очереди, до любой макрозадачи. Очередь продолжает опустошаться, пока действительно не станет пустой.

Promise.resolve().then(() => {
  console.log('micro A');
  Promise.resolve().then(() => console.log('micro B (added later)'));
});
setTimeout(() => console.log('macro'), 0);
console.log('sync');

Разрешённые значения передаются дальше

Значение, возвращённое обработчиком .then, становится входным значением для следующего обработчика в цепочке — всё это выполняется через микрозадачи.

Promise.resolve(2)
  .then(n => n * 3)
  .then(n => n + 1)
  .then(n => console.log('result', n));
console.log('sync first');

async/await использует микрозадачи

Код после await возобновляет выполнение как микрозадача. Поэтому продолжение после ожидания выполняется до таймера, поставленного в очередь раньше.

async function run() {
  console.log('a');
  await null;
  console.log('c (after await)');
}
setTimeout(() => console.log('d (timeout)'), 0);
run();
console.log('b');

Общий пример порядка выполнения

Объединим всё вместе. Предскажите порядок: сначала синхронное выполнение, затем все микрозадачи, затем макрозадача.

console.log('1 sync');
setTimeout(() => console.log('5 timeout'), 0);
Promise.resolve().then(() => console.log('3 promise'));
Promise.resolve().then(() => console.log('4 promise'));
console.log('2 sync');

Почему истощение микрозадач опасно

Поскольку микрозадачи всегда выполняются до макрозадач, микрозадача, которая бесконечно ставит в очередь новые микрозадачи, может заблокировать таймеры и отрисовку. Цепочки микрозадач должны быть конечными.

let n = 0;
function loop() {
  if (n++ < 3) {
    console.log('micro ' + n);
    Promise.resolve().then(loop);
  }
}
setTimeout(() => console.log('macro after micros'), 0);
loop();

Почему этот порядок важен

Знание о том, что микрозадачи выполняются до макрозадач, объясняет, почему результаты промисов появляются до обратных вызовов таймеров и почему возникают ошибки в порядке выполнения. Правило простое: синхронное выполнение, затем обработка всех микрозадач, затем одна макрозадача — и повторить.

console.log('A');
Promise.resolve().then(() => console.log('B'));
setTimeout(() => console.log('D'), 0);
console.log('C');

Быстрая проверка

Обратный вызов .then промиса и setTimeout(fn, 0) ожидают выполнения. Что выполнится первым?

Итоги: микрозадачи и промисы

Вы усвоили правило приоритета:

  • Микрозадачи создаются промисами и queueMicrotask.
  • Вся очередь микрозадач обрабатывается до любой макрозадачи.
  • Продолжения async/await являются микрозадачами.
  • Бесконечные цепочки микрозадач могут блокировать таймеры и отрисовку.

Часто задаваемые вопросы

Урок «Микрозадачи и промисы» бесплатный?

Да — полный текст урока «Микрозадачи и промисы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс JavaScript Academy, подпишись на CoddyKit PRO. Курс JavaScript Academy содержит 4 уроков всего.

Чему я научусь в уроке «Микрозадачи и промисы»?

Узнайте, почему обратные вызовы промисов выполняются первыми. Ты практикуешь JavaScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать JavaScript Academy?

Предыдущий опыт не требуется. JavaScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Микрозадачи и промисы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке JavaScript Academy?

Да. Каждый урок JavaScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Стек вызовов
  2. Макрозадачи и очередь задач
  3. Микрозадачи и промисы
  4. queueMicrotask и порядок выполнения
← Назад к JavaScript Academy