awesome-everything EN
↑ Обратно к восхождению

Производительность

Что на самом деле стоит bundle: download, parse, compile, execute

Суть 1 МБ JS-bundle — это не 1 МБ цены. Это четыре последовательных CPU-фазы, которые на mid-range mobile в 4-8 раз тяжелее, чем на ноутбуке разработчика.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 12 min

Разработчик выпускает новую фичу в пятницу. На MacBook страница грузится за 800 мс — нормально. К понедельнику bounce rate вырос на 20%. Коллега тестирует на mid-range Android и 8 секунд смотрит в белый экран. Фича была в порядке. Bundle — нет.

Четыре фазы, одна цена

Когда браузер скачивает JavaScript-файл, он не просто «грузит» код. До первого возможного взаимодействия выполняются четыре последовательные фазы.

Download — байты идут по сети. На 4G 200 КБ gzip’d занимает 150-500 мс в зависимости от качества сигнала.

Parse — JS-движок проходит по каждому байту и строит абстрактное синтаксическое дерево (AST). V8 парсит примерно 1-2 МБ/сек на быстром laptop-CPU и лишь 200-400 КБ/сек на среднем Android. Bundle 500 КБ uncompressed занимает 1,5-2 с parse на mid-range mobile.

Compile — движок преобразует AST в байткод, затем в оптимизированный машинный код. V8 использует многоуровневый пайплайн (Ignition → Sparkplug → TurboFan). Стоимость компиляции примерно линейно зависит от количества кода, реально запущенного при старте.

Execute — top-level код bundle’а выполняется синхронно: инициализация фреймворка, создание store, регистрация роутов. Для типового React + Redux приложения это блокирует main thread на 100-500 мс.

Полная цепочка на mid-range mobile для bundle 500 КБ uncompressed: download 800 мс + parse 1,5 с + compile 300 мс + execute 400 мс = примерно 3 секунды до первого возможного клика. Каждая фаза — отдельный рычаг; ни одна не поможет без прямого адресования.

ФазаУзкое местоЦена на mid-range mobile (500 КБ uncompressed)
DownloadNetwork bandwidth~800 мс на 4G
ParseCPU — V8 проходит каждый байт~1,5-2 с
CompileCPU — JIT-уровни~300 мс
ExecuteCPU — single-threaded старт~400 мс

Почему «работает на моём ноутбуке» — ложный тест

MacBook M-series имеет single-thread CPU в 4-8 раз быстрее среднего Android (Snapdragon 6 или 7-серия). 5G или Wi-Fi помогут с download — но parse, compile и execute выполняются целиком на CPU юзера. Более быстрая сеть не двигает эти фазы ни на миллисекунду.

Большинство пользователей в глобальных рынках — на mid-range или старом железе. Команды, тестирующие только на флагманах или dev-машинах, систематически недооценивают реальный опыт юзера. Chrome DevTools имеет режим CPU throttling 4x, приближающий mid-range Android; его использование при каждой performance-проверке ловит разрыв до продакшна.

Дисциплина bundle budget

Bundle budget — максимальное количество байтов (обычно gzip’d JS, CSS, images раздельно), которое route имеет право доставлять, enforce’ится в CI. Без бюджета размер bundle растёт по accretion: каждый инженер добавляет библиотеку, каждая добавляет несколько КБ, ни один PR не виноват, но через полгода bundle удвоился. С бюджетом каждый PR, превышающий cap, fail’ит CI — команда либо оправдывает добавление, либо находит меньшую альтернативу.

Бюджет конвертирует performance из намерения в constraint. Он делает для клиентских байтов то же, что SLO делает для серверной latency: делает её измеримой, enforced и owned.

Почему это работает

Почему 1 МБ JS стоит дороже 1 МБ image? Image скачивается, декодируется GPU и рисуется. JS скачивается, затем парсится, компилируется и выполняется на CPU — три дополнительных фазы, медленных, последовательных, блокирующих main thread. За байт JS примерно в 5-10 раз дороже image на mid-range mobile.

Викторина

Bundle 500 КБ uncompressed грузится нормально за 400 мс на dev-ноутбуке. Оцени вероятный Time to Interactive на mid-range Android на 4G.

Расставь шаги по порядку

Расставь lifecycle JS bundle'а от сетевого запроса до первого взаимодействия:

  1. 1 Браузер запрашивает JS-файл с сервера
  2. 2 Сервер возвращает файл (часто сжатый gzip или brotli)
  3. 3 Браузер распаковывает и получает байты
  4. 4 JS-движок парсит байты в abstract syntax tree (AST)
  5. 5 JS-движок компилирует AST в байткод и затем в оптимизированный машинный код
  6. 6 Браузер выполняет top-level код: imports, side effects, инициализация фреймворка
  7. 7 App достигает interactive состояния — юзер может кликнуть
Викторина

Команда переходит с gzip на brotli, bundle с 180 КБ до 150 КБ transferred. LCP улучшается на 50 мс. Решена ли проблема bundle?

Вспомните перед уходом
  1. 01
    Назови четыре фазы, которые JS bundle проходит до interactive страницы.
  2. 02
    Почему апгрейд до 4G не исправляет parse и compile время?
  3. 03
    Что такое bundle budget и что он предотвращает?
Итог

JavaScript bundle запускает четыре последовательных CPU-фазы: download, parse, compile, execute. Первая — network-bound; остальные три — CPU-bound и в 4-8 раз медленнее на среднем Android, чем на dev-ноутбуке. Bundle 500 КБ uncompressed может стоить 3 секунды заблокированного main thread на mid-range mobile — невидимо в разработке. Bundle budgets делают цену per-route constraint, enforce’ируемым в CI, ловя дрейф до юзеров. Следующий урок связывает эти цены с Google Core Web Vitals и конкретными порогами, определяющими «хорошо» vs «плохо» для LCP, INP и CLS.

Связанные уроки
встречается в159
Продолжить восхождение ↑Core Web Vitals: LCP, INP и CLS
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.