Проект ЦИТадель
Советы «сжать изображения», «отложить сценарии» и «включить кэш» полезны только после ответа на два вопроса: какое действие пользователя задержано и на что уходит время. Рабочая станция разработчика, близкий сервер и прогретый кэш редко представляют всю аудиторию. Поэтому производительность рассматривают как распределение полевых наблюдений, а локальный профиль используют для объяснения конкретного участка этого распределения.
Для разбора задержки удобно считать три вида затрат: последовательные ожидания сети, передаваемые байты и работу процессора. Это не точная формула — операции перекрываются, транспорт зависит от потерь и приоритетов, а серверное ожидание требует собственного разбора, — но такая модель помогает найти преобладающую причину. Далее она применяется к загрузке, отклику на действия и стабильности раскладки, а в конце превращается в воспроизводимый практикум и бюджет производительности.
Три стабильные метрики Core Web Vitals описывают разные стороны опыта:
Для оценки Core Web Vitals эти границы проверяют на 75-м перцентиле посещений, отдельно для мобильных и настольных устройств. Это не делает p75 универсальным показателем всякой задержки: для критичного сценария команда может дополнительно следить за p90 или p95, регионами, маршрутами, версиями приложения и классами устройств. Среднее скрывает тяжёлый хвост, а один общий перцентиль способен скрыть медленный сегмент.
Полевые данные показывают реальные устройства, сети, кэш и взаимодействия, но требуют достаточной выборки, контроля версии и соблюдения правил приватности. Лабораторный прогон воспроизводим и даёт водопад и профиль, однако выбранное дросселирование — модель, а не имитация конкретного перцентиля аудитории. Эти способы дополняют друг друга: поле находит проблему и её масштаб, лаборатория помогает воспроизвести причину.
На временной шкале полезно отмечать:
До первого байта документа добавляется обработка на сервере: очереди, обращения к хранилищам и формирование ответа. Сетевое расстояние имеет физический нижний предел, но на практике задержку увеличивают также маршрутизация и очереди. Нельзя заранее объявить один вид затрат главным: в медленной сети решающим может быть изображение, на слабом устройстве — сценарий, а при холодном серверном кэше — работа приложения. Приоритет определяется трассой конкретного пользовательского результата.
Для LCP удобно нарисовать цепочку от навигации до появления его элемента: документ, обнаружение ресурса, доставка и задержка рендеринга. В водопаде ищут зависимости, которые нельзя выполнить одновременно:
defer или async останавливает разбор HTML. Решение зависит от порядка и зависимостей: убрать неиспользуемое, доставить необходимые стили раньше, поставить независимый сценарий позже или применить defer. Модульный сценарий по умолчанию откладывает выполнение, но его зависимости тоже нужно доставить.preload. preconnect заранее создаёт дорогое соединение, поэтому его оставляют для малого числа подтверждённых критических источников.CDN сокращает путь и разгружает источник для кэшируемого ответа, если попадание в кэш действительно происходит. HTTP/2 мультиплексирует потоки одного соединения; HTTP/3 переносит их на QUIC, где потеря пакета одного потока не задерживает доставку данных остальных потоков на уровне транспорта. Низкая задержка установления соединения возможна при подходящих условиях, но 0-RTT доступен не для первого контакта и имеет ограничения повторного воспроизведения. Подробнее протоколы разобраны в статье «HTTP/2 и HTTP/3».
Сначала различают исходный размер, размер после сжатия и фактически переданный объём. Изображения готовят в подходящем формате и качестве, а srcset и sizes позволяют выбрать вариант под область отображения и плотность экрана. Выигрыш AVIF, WebP или другого формата проверяют на конкретном материале: качество и скорость декодирования тоже входят в результат. Для шрифта выбирают нужные начертания и наборы символов, не забывая о лицензии и поведении запасного шрифта.
Атрибуты width и height изображения задают соотношение сторон, чтобы браузер зарезервировал место до загрузки. Аналогично резервируют место для рекламы, встроенных документов и динамических блоков. Это снижает CLS, но не исправляет сдвиг, вызванный вставкой нового содержимого над уже показанным.
Повторную передачу контролирует HTTP-кэш. Ресурс с хешем содержимого в URL можно считать неизменяемым и отдавать с длительным max-age и immutable; новое содержимое получает новый URL. HTML и меняющиеся данные обычно требуют более короткой свежести или условной проверки с ETag. Персонализированный ответ нельзя бездумно помещать в общий кэш: директивы private, public, no-store и ключ Vary являются частью модели безопасности и корректности. Сборка версионированных ресурсов связана с правилами статьи «Инженерный конвейер».
Перед исполнением JavaScript необходимо передать, разобрать и скомпилировать; браузер может выполнять часть подготовки вне главного потока, но код страницы и большинство операций DOM выполняются на нём. Там же планируются значительная часть вычисления стилей, раскладки и подготовки кадра. Длинная задача задерживает обработчик ввода или следующий кадр и ухудшает INP. Устройство этого цикла рассмотрено в статьях «Как устроен браузер» и «Современный JavaScript и TypeScript».
Размер сценария служит полезным бюджетом, но не заменяет профиль: одинаковое число байтов может выполнять разный объём работы. Последовательность действий такова:
Гидратация большого дерева является одним из возможных источников работы, но не единственным. Повторный рендеринг, синтаксическая подсветка, аналитика, сторонняя реклама и сложная раскладка могут быть важнее. Варианты рендеринга и гидратации разобраны в статье «Как устроен фронтенд-фреймворк».
Одинаковое полное время может восприниматься по-разному. Сначала показывают полезное содержимое, а не второстепенные блоки; после действия немедленно меняют состояние кнопки или сообщают о ходе операции; место позднего содержимого резервируют заранее. Индикатор и скелетон должны отражать реальную работу, быть доступны вспомогательным технологиям и не задерживать уже готовый результат.
Оптимистическое обновление сокращает ощущаемое ожидание, если операция обычно успешна и интерфейс умеет ясно показать отказ и восстановить состояние. Для необратимого платежа такая техника требует иной осторожности, чем для отметки пункта списка. Восприятие не заменяет сокращение времени: оно определяет, какую полезную информацию и контроль пользователь получает во время неизбежного ожидания.
Небольшие добавления накапливаются: сценарий аналитики, ещё одно начертание шрифта, новый компонент и сторонний виджет по отдельности могут не изменить субъективный прогон. Поэтому требования превращают в бюджеты: сжатые байты JavaScript и CSS на маршрут, число критических источников, допустимое изменение лабораторного LCP или длительность выбранного взаимодействия. Стабильные показатели вроде размера удобно проверять на каждом изменении. Временные метрики шумят, поэтому для них фиксируют окружение, повторяют прогоны и сравнивают статистику, а не одно значение.
Полевые цели описывают результат для аудитории, лабораторные бюджеты защищают известные причины, но одно не является прямой заменой другого. Поле отвечает, какие сегменты испытывают задержку; лабораторная трасса — где искать работу. Владелец продукта определяет допустимый обмен между новой возможностью и затратами, а сторонний код проходит тот же контроль, что собственный. Эта схема продолжает подходы статей «Наблюдаемость» и «Инженерный конвейер».
Выберите страницу и один важный сценарий. Записывайте версию браузера, профиль сети и процессора, размер окна, холодный или прогретый кэш. Без одинаковых условий сравнение до и после не имеет смысла.
Задание 1. Базовая линия. Выполните не менее пяти холодных и пяти повторных лабораторных прогонов с одним профилем. Запишите LCP и CLS, затем воспроизведите важное действие и измерьте его задержку в профиле. Не называйте этот прогон p75 аудитории. Если доступны полевые данные, отдельно запишите их p75 и сегменты.
Задание 2. Разложение LCP. Найдите LCP-элемент и разделите время на TTFB, задержку обнаружения ресурса, длительность его загрузки и задержку рендеринга. Для текстового LCP ресурс может отсутствовать; тогда исследуйте блокирующие стили, шрифт и работу главного потока. По Navigation Timing отделите создание соединения от ожидания ответа.
Задание 3. Медленное действие. В записи важного взаимодействия найдите задержку до обработчика, само выполнение и время до следующего кадра. Отметьте длинные задачи, принудительную раскладку и сторонний код. Отчёт покрытия используйте только как список кандидатов на разделение или удаление.
Задание 4. Сдвиги. Включите отображение областей сдвига и перезагрузите страницу. Для каждого заметного вклада CLS найдите незарезервированное изображение, встраиваемый блок, позднюю вставку или замену шрифта. Исправьте один источник и проверьте, что исчез именно его вклад, а не только изменился порядок загрузки.
Задание 5. Два изменения. Выберите две причины из разных групп: например, устраните позднее обнаружение LCP-изображения и сократите длинную задачу обработчика. Меняйте по одной причине, повторяйте серию прогонов и сравнивайте медиану и разброс. Проверьте отсутствие ухудшения других метрик и правильность поведения при ошибке сети.
Задание 6*. Бюджет. Добавьте проверку сжатого размера сценариев маршрута и стабильный лабораторный сценарий. Задайте допустимое отклонение с учётом шума, сохраните диагностический отчёт и сделайте сообщение проверки предметным: какой ресурс или этап превысил предел. Полевой сбор добавляйте только при наличии полномочий, срока хранения и правил приватности.