В целом я вижу асинхронность в js как-то так:
V8 идет по скрипту
Собирает информацию о текущем скоупе: Все объявления переменных и функций. Всё это регистрируется в Heap.
Затем проходит ещё раз сверху-вниз и собирает все вызовы.
Каждый встречный вызов помещает в Call Stack
Когда КолСтек заполнен начинается его обработка.
КолСтек начинает отрабатывать, каждый вызов берётся и создает для себя локальный скоуп, который компилируется V8 в машинный код. (Образуются ветки скоупов от глобального которые удаляются мусорщиком когда на них не остаётся линков)
Когда встречаются код представляющий из себя асинхронный элемент (вроде setInterval и тд полагаю есть ещё варианты вроде запросов к Воркерам)
Всё это закидывается на сторону "ПодДвижков" : WebAPI и Воркеров созданных кодом.
Когда они дают зелёный свет и выполняют делегированные инструкции они закидывают результат в Event Loop.
Как только Call Stack окажется пустым Event Loop начнёт по 1 элементу закидывать в него результаты исполнений асинхронных функций, которые запишутся в те места Heap`a из которых они были делегированы.