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 выполняется между ними и это значение не подменяет.
- 5.1Синхронный код, микротаск, таймер
- 5.2Тело промиса синхронно
- 5.3await отдаёт управление
- 5.4Две очереди: микротаски и таймеры
- 5.5throw, catch, finally, затем then
- 5.6Три then на одном промисе против цепочки
- 5.7queueMicrotask и then — одна и та же очередь
- 5.8for с await против forEach
- 5.9async без return: что приходит в await
- 5.10throw в async до первого await
- 5.11Promise.all с таймерами
- 5.12Микротаск внутри микротаска против таймера
- 5.13Отказ течёт вниз до ближайшего catch
- 5.14Таймер внутри then и then внутри таймера
- 5.15then возвращает промис — цепочка ждёт
Задачи из сборки