Споры о скорости сайта заканчиваются там, где начинается измерение. Красивая гипотеза о тяжёлом скрипте проигрывает одному взгляду на водопад загрузки: половина времени уходит на ожидание ответа сервера, треть - на загрузку одного изображения, и лишь остаток на всё остальное. Оптимизация по-ветерански начинается не с микроуправления байтами, а с честного разложения задержки на слои и атаки на самые толстые из них. Быстрый сайт - это не набор трюков, а дисциплина: бюджет производительности, измерение на реальных пользователях и защита достигнутого от медленной деградации.

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

Критический путь рендеринга определяет судьбу первого экрана

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

<link rel="stylesheet" href="/critical.css">
<link rel="preload" as="style" href="/full.css" onload="this.rel='stylesheet'">
<script defer src="/app.js"></script>

Критические стили инлайнятся прямо в разметку, полные грузятся асинхронно, скрипты получают отложенное исполнение. Приём известен лет десять и остаётся рабочим, потому что физика не изменилась: страница рисуется тогда, когда собран каркас, и каждый лишний блокирующий ресурс отодвигает момент.

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

Порядок и объём разметки - вторая половина пути. Первые килобайты ответа обязаны нести главное: заголовок, первый экран, начало содержимого. Серверная часть управляет этим потоковой отдачей, когда каркас уходит в браузер до сбора всей страницы. Долгие запросы к базам в середине шаблона блокируют отдачу, и вынос таких запросов в начало с параллельным исполнением сокращает время до первого байта без единого изменения во фронтенде.

Изображения дают самую большую победу за вечер

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

<img src="/photo-480.avif" srcset="/photo-480.avif 480w, /photo-960.avif 960w, /photo-1440.avif 1440w"
     sizes="(max-width: 48em) 92vw, 40vw"
     width="1440" height="960"
     loading="lazy" decoding="async" alt="Рабочее место">

Атрибуты размеров резервируют место и убирают скачки вёрстки, из-за которых посетитель промахивается по кнопке во время загрузки. Первый экран - единственное место, где ленивая загрузка запрещена: главный кадр получает высокий приоритет и предзагрузку, всё остальное по касанию.

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

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

Кэш и доставка через сеть превращают расстояние в ноль

Физика неумолима: запрос из города до сервера в другом полушарии стоит сотни миллисекунд только на дорогу туда и обратно. Сеть доставки содержимого ставит копии статических файлов рядом с посетителем, и вместо кругосветки файл приезжает с соседней точки. Настроенный кэш браузера убирает и эти миллисекунды для повторных визитов: файлы с дальними сроками годности не запрашиваются заново.

Правила кэширования пишутся явно и проверяются по заголовкам ответа. Иммутаемые файлы со снимком содержимого в имени получают срок годности в год, страницы и интерфейсы обновляются по условным запросам. Ошибки здесь стоят незаметно: слишком короткий срок плодит лишние запросы, слишком длинный без версионирования приносит посетителям старые файлы после релиза.

Кэш на сервере завершает тройку уровней: результаты тяжёлых операций сохраняются с чистым ключом и честным сроком, а сбой внешнего сервиса не ломает страницу, потому что вчерашний ответ ещё лежит в хранилище. Такая устойчивость для нагруженного проекта ценнее самих миллисекунд.

Сервис-воркер доводит кэширование до браузера: страница собирается из локальных копий даже при пропавшей сети, а обновления приходят в фоне. Для витрины или медиа-каталога это оборачивается мгновенными повторными визитами и работой в лифте. Готовность к оффлайну не самоцель, а побочный эффект грамотного слоя кэша, и стоит он двух десятков строк конфигурации.

Скрипты требуют бюджета и права остаться в фоне

Ява-скрипт - самый дорогой ресурс страницы: его нужно скачать, разобрать и исполнить, и на слабом телефоне каждый этап в разы дороже, чем на ноутбуке разработчика. Третий-партейшие счётчики, чаты, виджеты и пиксели складываются в нагрузку, которую никто не считал, потому что каждый добавлялся по отдельности и с добрыми намерениями. Аудит сторонних скриптов - регулярная гигиена: каждый виджет объясняет свою метрическую ценность, и те, что не подтверждаются, уходят.

Собственный код дисциплинируется бюджетом на сборку: главный файл умещается в договорённый размер, тяжёлые части грузятся по маршруту - калькулятор на странице калькулятора, редактор в момент редактирования:

button.addEventListener("click", async () => {
  const { openEditor } = await import("./editor.js");
  openEditor();
});

Динамический импорт привозит код тогда, когда он понадобился, и страницы без редактора за него не платят. Тот же принцип работает для данных: запрашивается то, что нужно следующему экрану, а не всё подряд на всякий случай.

Показатели интерактивности замыкают тему скриптов. Долгие задачи процессора замораживают реагирование на нажатия, и разбивка монолитных вычислений на короткие порции с возвратом управления между ними удерживает страницу отзывчивой. Пользователь не видит графики, он чувствует: кнопка отвечает мгновенно или нет, и это ощущение и есть цель.

Тяжёлые вычисления переезжают в воркеры: сортировка тысячи записей или пересчёт таблицы в фоновом потоке оставляет интерфейс живым. Обмен с воркером строится сообщениями, и дисциплина проста: всё, что рискует занять больше кадра анимации, обязано покинуть главный поток. Именно так длинные списки перестают подвешивать страницу на телефоне среднего класса.

Метрики реальных пользователей честнее лабораторных тестов

Лабораторный прогон показывает пики и провалы в контролируемых условиях, но живой интернет другой: телефоны среднего класса, сотовые сети, десять открытых вкладок. Программа сбора полевых данных отвечает на вопрос, каково посетителям на самом деле, и смотрит на перцентили, а не на средние: семьдесят пятый процентиль отделяет здоровую половину опыта от хвоста, которым и занимаются.

Три метрики первого экрана стали стандартом индустрии: задержка до появления главного содержимого, время до первого отклика на действие, устойчивость вёрстки при загрузке. Каждая имеет пороги и лечится своим набором приёмов, и разложение опыта на эти три числа позволяет разговаривать о скорости без философии. Падение одной метрики после релиза локализует проблему до класса причин за минуты.

Время до первого байта стоит отдельного контроля, потому что оно обнуляет все фронтендовые усилия: страница не может показаться раньше, чем сервер начал отвечать. Причины лежат на серверной стороне - медленные запросы, далёкий дата-центр, отсутствие кэша ответов, и лечатся соответственно: индексы, потоковая отдача, доставка ближе к аудитории. Водопад загрузки честно показывает, где ждёт посетитель, и первые триста миллисекунд там чаще всего серверные.

Полевые данные связываются с выпусками: каждой версии приписываются её показатели, и регрессия видна в разрезе, а не в ощущениях. Команда, которая смотрит на одну и ту же страницу в разных версиях релиза, перестаёт спорить и начинает считать.

Лаборатория при этом не отменяется: прогон на стенде ловит регрессию до релиза, полевые данные подтверждают или опровергают её у живой аудитории. Пара из стенда и поля - минимальный комплект контроля: один смотрит в будущее, вторая в настоящее.

Бюджет производительности защищает результат от деградации

Главная болезнь скорости - не отсутствие техник, а постепенная утечка: каждый релиз добавляет чуточку, и через год страница весит вдвое больше без единого злого умысла. Бюджет превращает скорость в число с владельцем: страница весит не больше стольких-то килобайт, главный файл не больше стольких-то, сторонних скриптов не больше стольких-то. Превышение бюджета не проходит молча - конвейер сообщает об этом при сборке.

Бюджет записывается в конфигурации и проверяется автоматически:

{
  "budgets": [
    { "type": "transferSize", "maximum": 170000 },
    { "type": "script", "maximum": 85000 },
    { "type": "third-party", "maximum": 30000 }
  ]
}

Дисциплина бюджета работает как замки на дверях: она не делает здание быстрее, она не даёт ему медленно разваливаться. Скорость, однажды достигнутая, поддерживается без героизма, и это поддержание и есть ветеранский уровень, отличающий проект с культурой от проекта с удачным кварталом.

Культура бюджета дополняется регулярными аудитами: раз в квартал полный проход по странице с водопадом, списком сторонних скриптов и весами. Аудит находит то, что бюджет пропустил: виджет, который умножился после рефакторинга, картинку, пробравшуюся мимо конвейера. Час аудита в квартал дешевле недели расследования, почему страница стала медленной, и каждое следующее поколение страниц наследует не только скорость, но и привычку её удерживать.

Порядок работ определяет отдачу от вложений

Практика выстроила устойчивый порядок приоритетов, при котором каждый час работы даёт максимум эффекта. Сначала серверное время ответа, потому что оно держит всё остальное. Затем изображения и шрифты как главные веса. Затем скрипты и порядок их исполнения. Затем кэши и доставка. Микрооптимизации идут в конце и только по измерениям:

  1. замер и разложение задержки по слоям;
  2. серверное время ответа и порядок разметки;
  3. изображения, шрифты и критические стили;
  4. скрипты с бюджетом и отложенной загрузкой;
  5. кэши всех трёх уровней и сеть доставки;
  6. полевые метрики с контролем по релизам;
  7. бюджет в конвейере как страховка от деградации.

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