Gernar
JavaScript: асинхронность

В какой последовательности выполняются Promise и setTimeout

Разбор вопроса «В какой последовательности выполняются Promise и setTimeout» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.

Вопрос

В какой последовательности выполняются Promise и setTimeout

Профессия

Frontend Developer

Что хочет услышать интервьюер

Интервьюер хочет убедиться, что кандидат понимает разницу между микротасками и макротасками, а также порядок выполнения задач в Event Loop. Важно показать знание того, как Promise и setTimeout взаимодействуют в асинхронной модели JavaScript.

Ключевые тезисы

  • JavaScript имеет однопоточную модель выполнения, где задачи обрабатываются в порядке их поступления в очередь событий.
  • Promise и setTimeout относятся к разным типам задач: Promise — это микротаски, а setTimeout — макротаски.
  • Микротаски (например, Promise) выполняются перед макротасками (например, setTimeout), даже если они добавлены позже.
  • Внутри одного типа задач (например, микротаски) порядок выполнения строго соответствует порядку их добавления.
  • Пример: если setTimeout и Promise добавлены одновременно, сначала выполнится код внутри Promise, а затем callback из setTimeout.

Подробный ответ

JavaScript использует однопоточную модель выполнения, где задачи обрабатываются через очередь событий (Event Loop). Эта очередь делится на микротаски (microtasks) и макротаски (macrotasks). Promise относится к микротаскам, а setTimeout — к макротаскам. Микротаски выполняются сразу после текущего синхронного кода, даже если они были добавлены позже макротаск. Это означает, что callback из Promise выполнится раньше, чем callback из setTimeout, даже если setTimeout имеет нулевую задержку. Принцип работы Event Loop гарантирует, что все микротаски будут обработаны перед переходом к следующей макротаске. Это важно для понимания порядка выполнения асинхронного кода.

Практические примеры

Пример 1

Пример 1:

console.log('Start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('End');

Вывод: Start End Promise setTimeout

Пример 2

Пример 2:

setTimeout(() => console.log('Timeout 1'), 0);
Promise.resolve().then(() => {
  console.log('Promise 1');
  setTimeout(() => console.log('Timeout inside Promise'), 0);
});
Promise.resolve().then(() => console.log('Promise 2'));
setTimeout(() => console.log('Timeout 2'), 0);

Вывод: Promise 1 Promise 2 Timeout 1 Timeout 2 Timeout inside Promise

Частые ошибки

  • Ошибка: предположение, что setTimeout с нулевой задержкой выполнится сразу после синхронного кода. На самом деле, он попадает в очередь макротаск и ждет выполнения всех микротаск.
  • Ошибка: непонимание, что вложенные микротаски (например, Promise внутри другого Promise) будут выполняться до перехода к следующей макротаске.

Связанные темы

  • Event Loop в JavaScript
  • Разница между микротасками и макротасками
  • Асинхронность в JavaScript: async/await, callbacks, Promise
  • Работа с Web APIs (setInterval, requestAnimationFrame, etc.)

Follow-up вопросы

Что такое очередь событий и как она работает в JavaScript?

Уровень: basic

Очередь событий — это механизм, который управляет выполнением задач в JavaScript. Она обрабатывает задачи в порядке их поступления, разделяя их на микротаски и макротаски.

Почему микротаски выполняются перед макротасками?

Уровень: intermediate

Микротаски выполняются перед макротасками, потому что они имеют высший приоритет в очереди событий. Это позволяет обрабатывать асинхронные операции, такие как Promise, сразу после завершения текущего синхронного кода.

Как работает выполнение задач внутри одного типа (например, микротаски)?

Уровень: basic

Внутри одного типа задач (например, микротаски) порядок выполнения строго соответствует порядку их добавления. Это гарантирует, что задачи выполняются последовательно, без смешивания.

Может ли setTimeout с нулевой задержкой выполняться раньше Promise?

Уровень: intermediate

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

Какие еще примеры микротаск и макротаск существуют в JavaScript?

Уровень: advanced

К микротаскам относятся Promise, process.nextTick (в Node.js), а к макротаскам — setTimeout, setInterval, события DOM и запросы к API.

Содержание