Основной поток браузера — дорогое удовольствие
6 сентября 2026 г.
3 мин
16

Основной поток браузера — дорогое удовольствие

Когда думают про оптимизацию фронтенда - вспоминают про сеть, бандл, кэш. Сократить запросы, уменьшить размер JS, настроить CDN. Это правильно и это работает.

Но есть вещь которую почти никто не упоминает - основной поток браузера. И есть причина почему о нём не говорят: на большинстве страниц он не становится проблемой.

Ровно до того момента когда становится.

Что такое основной поток

Браузер делает всё в одном потоке: разбирает HTML, выполняет JavaScript, реагирует на клики, обрабатывает анимации. Пока этот поток занят - страница не реагирует ни на что. Скролл зависает. Кнопки не нажимаются. Анимации дёргаются.

На простых страницах это незаметно - задачи короткие, поток успевает. Но стоит добавить сложную логику, стриминг данных, тяжёлые вычисления - и пользователь начинает чувствовать что сайт «тормозит».

При этом сеть работает нормально. Бандл маленький. Lighthouse зелёный. А всё равно что-то не так.

Шесть способов разгрузить поток

Splitting - разбить тяжёлую задачу на части. Если нужно обработать тысячу элементов - не делай это за один проход. Разбей на чанки по 50, давай потоку дышать между ними через setTimeout или scheduler.yield(). Пользователь не заметит паузы в 5мс, но заметит что интерфейс перестал реагировать на секунду.

Batching - группировать обновления. Вместо того чтобы обновлять DOM после каждого входящего события - собери изменения и примени разом. React делает это автоматически, но если работаешь напрямую с DOM или со стейтом вне React - про batching нужно думать самому.

Prioritizing - важное сначала. Не всё одинаково срочно. То что пользователь видит сейчас - важнее того что за пределами экрана. requestAnimationFrame для визуальных обновлений, requestIdleCallback для всего что можно отложить.

Deferring - откладывать незрительное. Аналитика, логирование, синхронизация данных которые не нужны прямо сейчас - всё это можно отложить. Браузер сам подскажет когда у него есть свободное время.

Compositor вместо JS для анимаций. CSS свойства transform и opacity браузер анимирует на уровне GPU без участия основного потока. Если двигаешь элемент через left и top - ты грузишь поток при каждом кадре. Если через transform: translate() - нет.

/* Грузит основной поток */
.element { left: 100px; }

/* Не грузит - всё на GPU */
.element { transform: translateX(100px); }

Web Workers - тяжёлые вычисления в отдельный поток. Парсинг большого JSON, поиск по данным, криптография - если это нужно делать в браузере, Web Worker позволяет вынести это из основного потока полностью. Главная оговорка: Worker не имеет доступа к DOM, только к чистым вычислениям.

Как это выглядит в реальном проекте

На своём сайте я добавил infinite scroll - заметки подгружаются при прокрутке. Первая реализация была прямолинейной: получил данные, сразу отрендерил всё.

На небольшом количестве заметок работало нормально. Когда заметок стало больше сотни - при прокрутке начало появляться лёгкое подёргивание. Сеть тут ни при чём - данные приходили быстро. Поток просто не успевал рендерить и одновременно реагировать на скролл.

Решение простое: рендерить чанками, давать браузеру время между вставками, не делать всё за один синхронный проход.

Главная мысль

Оптимизация это не только про байты которые летят по сети. Это ещё и про то что происходит после того как они долетели.

Основной поток - самый ограниченный ресурс фронтенда. Не потому что он медленный, а потому что он один. И всё что ты заставляешь его делать - он делает вместо того чтобы реагировать на пользователя. 🖥️