Files
frontend-docs/docs/browser/08-rerender_js.md

103 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
sidebar_position: 8
---
# Ререндер страницы в контексте 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).
Можно представить цикл так:
```text
[ Выполнение JS ] → [ Очередь microtasks ] → [ Пересчёт layout / repaint / composite ] → [ Следующий event loop tick ]
```
## 📅 Когда браузер решает перерисовать страницу
Браузер не будет рендерить страницу посреди выполнения JavaScript — это важно.
Рендеринг откладывается, пока:
- не закончится текущая макротаска,
- не будут выполнены все микротаски (Promise callbacks),
- и браузер решит, что пора обновить UI.
Например:
```js
console.log("start");
Promise.resolve().then(() => {
document.body.style.background = "red";
console.log("microtask done");
});
console.log("end");
```
Порядок событий:
```text
start
end
microtask done
[перерисовка после microtasks — фон становится красным]
```
## ⚙️ Пример с блокировкой рендера
Если ты сделаешь что-то тяжёлое в JS, например:
```js
while (true) {} // бесконечный цикл
```
— event loop не сможет дойти до стадии «рендера», и страница «замрёт».
Поэтому анимации, реактивные интерфейсы и плавные переходы требуют, чтобы JS отдавал управление обратно браузеру (через requestAnimationFrame, setTimeout, await, и т.д.).
## Как requestAnimationFrame вписывается в event loop
requestAnimationFrame (rAF) — это специальный API, который браузер вызывает перед следующей перерисовкой.
Это позволяет выполнять обновления DOM/Canvas синхронно с циклом рендера, без пропусков кадров.
```bash
→ 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 и рендера (в виде диаграммы)
<img src="images/08-rerender-phases.png" width="600"/>