Time to First Byte (TTFB) — это ключевой показатель веб-производительности, измеряющий время от момента запроса страницы до получения первого байта ответа от сервера. TTFB состоит из нескольких этапов: DNS lookup, установление TCP-соединения, TLS handshake (при HTTPS), и непосредственно время обработки запроса на сервере. Редиректы оказывают существенное влияние на TTFB, так как каждый перенаправляющий ответ добавляет задержку в цепочку запросов.
Каждый HTTP-редирект (например, 301 или 302) инициирует новый цикл запроса:
Таким образом, цепочка редиректов умножает задержку, поскольку TTFB измеряется для каждого отдельного запроса, но визуально пользователю отображается только время до загрузки окончательного содержимого. В реальных проектах длинные цепочки редиректов значительно ухудшают восприятие скорости страницы.
Библиотека Web Vitals предоставляет API для
измерения показателей производительности, включая TTFB через метрику
serverTiming. Стандартные события, такие
как PerformanceNavigationTiming и
PerformanceResourceTiming, позволяют получить детальные
данные по каждому шагу запроса.
Пример использования с учётом редиректов:
import { getTTFB } from 'web-vitals';
getTTFB((metric) => {
console.log('TTFB:', metric.value);
console.log('Запрос прошёл редиректы:', metric.entries[0].redirectStart, metric.entries[0].redirectEnd);
});
Ключевые моменты:
redirectStart и redirectEnd — времена
начала и конца всех редиректов.metric.value — чистый TTFB без учёта последующих
редиректов, но с учётом задержек на сервере.entries и суммировать интервалы
redirectEnd - redirectStart для каждого
перенаправления.Google учитывает TTFB как компонент Largest Contentful Paint (LCP). Длинные цепочки редиректов напрямую увеличивают LCP, что ухудшает метрики Core Web Vitals. В аналитике Web Vitals важно разделять:
navigation и resource событий.redirectStart и redirectEnd для
каждой метрики.const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'navigation') {
console.log('Redirects:', entry.redirectCount, 'Total Redirect Time:', entry.redirectEnd - entry.redirectStart);
console.log('TTFB конечного ресурса:', entry.responseStart - entry.startTime);
}
});
});
observer.observe({ type: 'navigation', buffered: true });