Skip to main content

Ререндер страницы в контексте event loop

Ререндер (перерисовка страницы) и event loop действительно тесно связаны в браузере, хотя происходят на разных уровнях работы движка.

🧠 Что такое event loop (цикл событий)

Event Loop — это механизм, который координирует выполнение JavaScript и обновление пользовательского интерфейса в браузере. Он следит за очередями задач (macrotasks и microtasks) и периодически синхронизирует результаты с рендерингом страницы.

Упрощённо:

  1. JS выполняется в однопоточном окружении.
  2. Когда движок сталкивается с асинхронной задачей (таймер, fetch, промис), она попадает в очередь.
  3. Event loop циклически:
    • берёт задачу из очереди макротасков (например, setTimeout, fetch, click),
    • выполняет её,
    • затем обрабатывает все микротаски (например, .then, queueMicrotask),
    • и только после этого может произойти рендер (отрисовка кадра).

🎨 Где тут ререндер страницы

Ререндер (или «перерисовка кадра») происходит между циклами event loop, после того как:

  • закончено выполнение всех JS-задач текущей итерации (включая microtasks),
  • браузер свободен,
  • и наступает момент обновления UI (обычно раз в 16,6 мс для 60 fps).

Можно представить цикл так:

[ Выполнение JS ] → [ Очередь microtasks ] → [ Пересчёт layout / repaint / composite ] → [ Следующий event loop tick ]

📅 Когда браузер решает перерисовать страницу

Браузер не будет рендерить страницу посреди выполнения JavaScript — это важно. Рендеринг откладывается, пока:

  • не закончится текущая макротаска,
  • не будут выполнены все микротаски (Promise callbacks),
  • и браузер решит, что пора обновить UI.

Например:

console.log("start");
Promise.resolve().then(() => {
document.body.style.background = "red";
console.log("microtask done");
});
console.log("end");

Порядок событий:

start
end
microtask done
[перерисовка после microtasks — фон становится красным]

⚙️ Пример с блокировкой рендера

Если ты сделаешь что-то тяжёлое в JS, например:

while (true) {} // бесконечный цикл

— event loop не сможет дойти до стадии «рендера», и страница «замрёт». Поэтому анимации, реактивные интерфейсы и плавные переходы требуют, чтобы JS отдавал управление обратно браузеру (через requestAnimationFrame, setTimeout, await, и т.д.).

Как requestAnimationFrame вписывается в event loop

requestAnimationFrame (rAF) — это специальный API, который браузер вызывает перед следующей перерисовкой. Это позволяет выполнять обновления DOM/Canvas синхронно с циклом рендера, без пропусков кадров.

→ JS выполняется
→ rAF callback запланирован
→ microtasks выполняются
→ браузер вызывает rAF callback
→ обновление layout/repaint
→ кадр готов

🧩 В контексте фреймворков (React, Vue и т.п.)

Когда React вызывает setState(), обновления не происходят мгновенно:

  • Они ставятся в очередь микрозадач или макрозадач (в зависимости от режима).
  • После завершения текущего JS-такта React вычисляет новый виртуальный DOM.
  • Затем браузер, на этапе рендера event loop, перерисовывает изменённые части UI.

Таким образом, event loop управляет моментом, когда обновления React реально становятся видимыми.

📊 Итоговое резюме

ЭтапЧто делает
MacrotaskВыполняет основную JS-задачу (скрипт, обработчик события и т.д.)
MicrotasksОбрабатывает все промисы и микрозадачи
Render phaseПосле JS — браузер вычисляет layout, стили и отрисовывает изменения
Next tickНачинается следующий цикл event loop

Визуальная схема event loop и рендера (в виде диаграммы)