05

Event loop и промисы

Синхронный код, потом микротаски, потом таймеры.

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

Тело промиса синхронно

Исполнитель new Promise(...) бежит сразу, в момент создания. Асинхронны не он, а колбэки then — они ставятся в очередь микрозадач. Поэтому console.log перед промисом, внутри исполнителя и в then напечатаются в порядке «до — тело — потом».

Очереди

  • Микрозадачи: колбэки then, продолжение после await, queueMicrotask.
  • Микрозадачи вычищаются все подряд, включая те, которые поставили друг друга. Очередь должна опустеть полностью.
  • Только после этого берётся одна макрозадача — таймер.

Отсюда классика: Promise.resolve().then(f) выполнится раньше setTimeout(g, 0), хотя задержка таймера нулевая.

`await` отдаёт управление

Код до await выполняется синхронно, код после него становится микрозадачей. Функция при этом приостанавливается, а не блокирует поток.

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

then пропускается, если в предыдущем звене выброшено исключение — управление уходит в ближайший catch. Значение, которое вернул catch, попадает в следующий then. finally выполняется между ними и это значение не подменяет.

  1. 5.1Синхронный код, микротаск, таймер
  2. 5.2Тело промиса синхронно
  3. 5.3await отдаёт управление
  4. 5.4Две очереди: микротаски и таймеры
  5. 5.5throw, catch, finally, затем then
  6. 5.6Три then на одном промисе против цепочки
  7. 5.7queueMicrotask и then — одна и та же очередь
  8. 5.8for с await против forEach
  9. 5.9async без return: что приходит в await
  10. 5.10throw в async до первого await
  11. 5.11Promise.all с таймерами
  12. 5.12Микротаск внутри микротаска против таймера
  13. 5.13Отказ течёт вниз до ближайшего catch
  14. 5.14Таймер внутри then и then внутри таймера
  15. 5.15then возвращает промис — цепочка ждёт

Задачи из сборки