Разбивка TTFB через NavigationTimingAttribution

Time to First Byte (TTFB) — один из ключевых показателей веб-производительности, измеряющий время от начала запроса страницы до момента, когда браузер получает первый байт ответа от сервера. Он критически важен для оценки отклика сервера и скорости загрузки страницы. В JavaScript с помощью библиотеки Web Vitals TTFB можно разбирать более детально, используя механизм NavigationTimingAttribution.

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

Основной объект доступен через API performance.getEntriesByType('navigation') и содержит набор атрибутов:

const [navigationEntry] = performance.getEntriesByType('navigation');
console.log(navigationEntry);

Ключевые свойства для анализа TTFB:

  • responseStart — время, когда браузер получил первый байт ответа.
  • requestStart — время, когда браузер отправил запрос на сервер.
  • connectStart и connectEnd — время начала и окончания TCP соединения.
  • domainLookupStart и domainLookupEnd — время DNS-запроса.
  • transferSize и encodedBodySize — размеры переданных данных, которые помогают оценить влияние сети.

Вычисление TTFB

TTFB рассчитывается как разница между моментом начала запроса и моментом получения первого байта ответа:

const ttfb = navigationEntry.responseStart - navigationEntry.requestStart;
console.log(`TTFB: ${ttfb} ms`);

Важный нюанс: responseStart включает сетевую задержку, время DNS и TCP, а также возможные дополнительные задержки из-за SSL/TLS. Это позволяет локализовать узкие места в цепочке запроса.

Разбивка TTFB на составляющие

Для подробного анализа TTFB можно разложить его на отдельные сегменты:

  1. DNS Lookup Time: dnsTime = navigationEntry.domainLookupEnd - navigationEntry.domainLookupStart

  2. TCP Connect Time: tcpTime = navigationEntry.connectEnd - navigationEntry.connectStart

  3. Request Time (Request Sent): requestTime = navigationEntry.responseStart - navigationEntry.requestStart

  4. SSL Handshake (если используется HTTPS): sslTime = navigationEntry.connectEnd - navigationEntry.secureConnectionStart

  5. Network Latency + Server Processing: serverTime = navigationEntry.responseStart - navigationEntry.connectEnd

Эта разбивка позволяет понять, какая часть TTFB приходится на сеть, а какая на сервер. Например, большое значение dnsTime может указывать на медленный DNS, а serverTime — на серверную нагрузку или медленное формирование ответа.

Интеграция с Web Vitals

Библиотека Web Vitals предоставляет функции для отслеживания ключевых показателей, включая TTFB через метрику LCP (Largest Contentful Paint) и CLS (Cumulative Layout Shift), однако для детальной диагностики серверной задержки используется кастомная логика на основе NavigationTiming:

import {getLCP} from 'web-vitals';

getLCP((metric) => {
  const [navEntry] = performance.getEntriesByType('navigation');
  const ttfb = navEntry.responseStart - navEntry.requestStart;
  console.log('TTFB через NavigationTiming:', ttfb);
  console.log('LCP:', metric.value);
});

Комбинируя TTFB с LCP и другими Web Vitals, можно получить полную картину производительности страницы, включая:

  • Влияние задержек сети на пользовательский опыт.
  • Задержки на стороне сервера.
  • Возможные узкие места при доставке контента.

Практическая оптимизация на основе NavigationTiming

  1. Сокращение DNS и TCP времени: использование CDN, оптимизация кэширования DNS, поддержка Keep-Alive.
  2. Снижение SSL/TLS задержки: применение современного TLS-протокола и минимизация числа сертификатов.
  3. Оптимизация серверной обработки: профилирование backend, использование кэширования, асинхронная генерация страниц.
  4. Кэширование на стороне клиента: настройка заголовков Cache-Control для уменьшения повторного TTFB.

Использование NavigationTimingAttribution позволяет не только измерять TTFB, но и системно локализовать проблемные участки цепочки загрузки страницы, что особенно важно при высоких требованиях к производительности.

Сбор и хранение метрик

Для комплексного анализа рекомендуется отправлять TTFB и другие временные показатели на сервер аналитики:

function sendMetrics() {
  const [navEntry] = performance.getEntriesByType('navigation');
  const metrics = {
    ttfb: navEntry.responseStart - navEntry.requestStart,
    dnsTime: navEntry.domainLookupEnd - navEntry.domainLookupStart,
    tcpTime: navEntry.connectEnd - navEntry.connectStart,
    sslTime: navEntry.secureConnectionStart ? navEntry.connectEnd - navEntry.secureConnectionStart : 0
  };
  fetch('/log-metrics', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(metrics)
  });
}

window.addEventListener('load', sendMetrics);

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