JavaScript – однопоточный язык.
Call Stack
Когда вызываем функцию в коде, JS помещает ее в стек сверху и затем выполняет ее.
Все функции, которые вызываются внутри этой функции, также будут добавлены в стек.
Когда функция завершается, она удаляется из стека.
Посмотрим пример выполнения синхронного кода.
Шаг 1.

Шаг 2.

Шаг 3.

Переполнение стека
Стек вызовов имеет максимальный размер. Его размер зависит от браузера и его версии.
Таким примером может стать рекурсия, тут получим ошибку переполнения стека.

Очереди браузера
Браузер поддерживает 3 очереди:
- Очередь микро задач
- Очередь отрисовки
- Очередь макро задач

Событийный цикл постоянно проверяет есть ли в этих очередях задачи, и когда стек вызовов пуст, он передает задачи на выполнение.
Шаг 1.

SetTimeout – это асинхронная задача. Для работы с таймерами в браузере Js использует Web API – это часть браузера, не JS.

JS видит SetTimeout, использует Web API для его выполнения

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

Как понять в какую очередь будет помещен колбек?

В очередь мирозадач попадают колбеки с “then, catch, finally, async (все асинхронные функции), queueMicrotask”. В очеред макрозадач попадут “SetTimeout, SetInterval, SetImmediate, window.addEventListener (события браузера)”.
Шаг 2.
Promise.resolve

Колбек попадает в очередь микротасок.

Шаг 3.
Console.log – это синхронный код, выполняется сразу.

Выполняется и удаляется с Call Stack.
Теперь Call Stack пуст. Каждый раз когда он пуст, будет выполнен следующий алгоритм.

- Берем задачу с очереди микрозадач и кидаем ее в Call Stack.
- Если очередь микрозадач оказалась пустой, то выполняем все задачи для отрисовки страницы.
- Если в очереди макрозадач есть хотя бы одна задача, берем первую задачу из очереди и помещаем ее в Call Stack.