Нажатие Enter запускает не один HTTP-запрос, а цепочку из нескольких сетевых, серверных и браузерных подсистем. Внутри разбор критического пути от DNS до рендеринга и ответ на вопрос почему Senior Fullstack читает весь маршрут целиком, а не только profiler своего фреймворка.
Содержание
TTFB ≠ скорость страницы: что именно измеряется
Открытие сайта — это не один HTTP-запрос. DNS, CDN, TLS, reverse proxy, application server, кэш, база данных и браузер — уже несколько независимых подсистем, которые частично работают параллельно. Даже приложение, написанное одним разработчиком на одном сервере, каждый раз проходит через этот маршрут целиком.
«200 мс» в этом материале — не обещание, что вся страница отрисуется за 200 мс. Это модель для анализа конкретного участка: Time to First Byte (TTFB), то есть времени до первого байта ответа сервера. web.dev рекомендует ориентироваться на ≤800 мс как общий ориентир для большинства сайтов, подчёркивая, что это не Core Web Vital: значение нужно интерпретировать в связке с FCP и LCP.
После TTFB браузеру ещё предстоит: скачать HTML полностью, обнаружить и загрузить CSS, JS, изображения и шрифты, выполнить JavaScript, построить Render Tree, сделать layout, paint, compositing. Для SPA это особенно критично: низкий TTFB может быть практически бесполезен, если браузеру предстоит большой объём клиентского рендеринга перед тем, как пользователь увидит контент.
Путь запроса схематично:
Браузер
├── cache / Service Worker?
├── DNS → IP
└── TCP или QUIC + TLS
↓
CDN / Edge
├── cache hit → ответ
└── cache miss
↓
Reverse Proxy → App Server
├── Redis / cache
├── PostgreSQL
└── business logic
↓
HTML / JSON
↓
Браузер: DOM → CSSOM → JS → Layout → Paint → Compositing
↓
LCP
Уже здесь понятно: TTFB = 200 мс совсем не означает, что пользователь увидел готовую страницу через 200 мс.
Browser cache и DNS: первый шаг
Пользователь вводит https://shop.example.com/catalog/42. До отправки первого байта в сеть браузер проверяет несколько локальных источников: HTTP cache, memory cache, disk cache, Service Worker, уже открытое соединение, DNS cache.
Поэтому два последовательных открытия одного URL дают разные waterfall — и это не баг. MDN отмечает, что DNS-результаты кэшируются, а разные hostname для шрифтов, изображений, скриптов и аналитики могут потребовать отдельных DNS lookup, каждый со своим TTL.
Для performance-инженера здесь важен не только сам протокол, но и число hostname на странице, длина CNAME-chain, география резолвера. При холодном старте (cold start) — полная цепочка рекурсивного резолвинга — DNS занимает 50+ мс. При закэшированном значении — 0 мс. Именно поэтому «DNS — главный тормоз» редко оказывается правдой: проблема почти всегда глубже.
TCP, QUIC и TLS: транспортный слой под капотом
Если соединения нет в кэше, браузеру нужно установить транспорт. Для классического HTTPS:
TCP handshake → TLS handshake → HTTP
Для HTTP/3:
QUIC (включает TLS 1.3) → HTTP/3
HTTP/3 — это не просто «HTTP/2, но быстрее». QUIC объединяет транспорт и TLS 1.3 в одном протоколе, реализует stream multiplexing и connection migration. RFC 9114 фиксирует low-latency connection establishment как одно из ключевых свойств стека: бороться с connection latency можно уже не только на уровне приложения, но и на уровне выбора протокола.
Для тёплого соединения TLS добавляет ≈0 мс — 0-RTT resumption и connection reuse делают повторный запрос значительно дешевле первого. Именно поэтому интерпретировать замеры производительности нужно с явным указанием типа соединения: cold или warm. Разница между ними в waterfall — принципиальная.
CDN и edge: самый быстрый запрос — тот, что не дошёл до origin
В production-архитектуре между браузером и backend почти всегда стоит CDN:
Browser → Edge
├── cache HIT → ответ без round trip к origin
└── cache MISS
↓
Load Balancer → Reverse Proxy → Application → DB
Если HTML или JSON уже закэширован на edge, запрос не доходит ни до приложения, ни до базы данных. Принцип прост: самый быстрый database query — тот, что не выполнялся. И второй: самый быстрый backend — тот, до которого запрос не дошёл.
Но CDN не спасёт динамический запрос, если ответ помечен Cache-Control: private, привязан к сессии или содержит персонализированный HTML. В таких случаях CDN вынужден идти к origin: выигрыш сводится к geographic proximity, но round trip до приложения никуда не исчезает.
Backend: routing, middleware, база данных
Допустим, cache miss. Запрос добрался до приложения:
GET /products/42 HTTP/2
Host: shop.example.com
Cookie: session=abc123
Accept: text/html
Внутри сервера путь:
router → middleware → authentication → business logic
↓
Redis (cache check)?
↓
PostgreSQL: SELECT id, name, price FROM products WHERE id = 42
↓
template / SSR → response
Проблема начинается, если SQL выполняется 300 мс без индекса, порождает N+1 queries, блокирует connection pool или ждёт внешний API. В таком сценарии оптимизация React-компонентов или сокращение bundle size полностью нерелевантны: пользователь ждёт не frontend, а ответа сервера.
N+1 queries — классическая ловушка: 1 запрос за списком объектов плюс N отдельных запросов для каждого из них. При 100 товарах и 10 мс на запрос — уже секунда задержки только на уровне базы. Типичное решение: один запрос с JOIN и грамотным индексом, либо батч-загрузка через WHERE id IN (...).
Браузер получает ответ: rendering pipeline
Браузер получает HTML — и здесь начинается уже не сетевая проблема, а браузерная. MDN подчёркивает: первоначальный HTTP-ответ порождает новые запросы к CSS, JavaScript, изображениям и другим sub-resources.
HTML → DOM
CSS → CSSOM
DOM + CSSOM → Render Tree → Layout → Paint → Compositing
Критический путь рендеринга (critical rendering path) — ресурсы, без которых браузер не может показать первый пиксель. Render-blocking JS и CSS удлиняют этот путь напрямую. LCP (Largest Contentful Paint) — метрика Core Web Vitals, которая фиксирует момент, когда пользователь увидел главный контент. Между 200 OK и LCP может пройти секунда и более. Фраза «сервер ответил 200 OK» не означает «сайт загрузился».
Практический кейс: как читать waterfall
Сценарий: интернет-магазин со стеком User → CDN → Nginx → Node.js/Nest.js → PostgreSQL.
Наблюдаемые метрики:
TTFB = 780 мс
LCP = 2,9 с
Первый инстинкт команды — уменьшить bundle React. Но waterfall в Chrome DevTools показывает другое:
DNS 12 мс
Connect 8 мс
TLS 11 мс
Request 3 мс
Waiting 746 мс ← здесь проблема
Receive 7 мс
Frontend ещё не начал работать. Profiling backend:
controller 5 мс
auth 12 мс
Redis 3 мс
PostgreSQL 680 мс
serialization 8 мс
Причина — тяжёлый SQL на таблице с миллионом строк без индекса. После добавления:
CREATE INDEX idx_products_category_created
ON products(category_id, created_at DESC);
Условный результат:
PostgreSQL: 680 мс → 24 мс
TTFB: 780 мс → 118 мс
Теперь оптимизация JS bundle и hydration становятся актуальными. Именно в таком порядке.
Стартовый инструмент для диагностики без DevTools:
curl -o /dev/null -s \
-w "DNS: %{time_namelookup}\n\
Connect: %{time_connect}\n\
TLS: %{time_appconnect}\n\
TTFB: %{time_starttransfer}\n\
Total: %{time_total}\n" \
Chrome DevTools → Network → Timing даёт полный waterfall: DNS, Connect, TLS, Waiting (TTFB), Content Download, а также Initiator и connection ID для анализа параллелизма запросов. Именно с этих двух инструментов начинается любая осмысленная диагностика производительности.
Четыре подводных камня
«200 OK означает, что сайт быстрый»
HTTP status 200 ничего не говорит о времени backend, TTFB, размере JS-bundle или моменте LCP. Это разные измерения из разных слоёв системы — подменять одно другим не стоит.
«DNS — главный тормоз»
На современных системах DNS часто кэширован: браузером, ОС, локальным резолвером. Если DNS занимает 5 мс, а PostgreSQL — 500 мс, оптимизация DNS ничего принципиально не изменит. Диагностику стоит начинать с Waiting-фазы в waterfall.
«Нужно просто поставить CDN»
CDN эффективен там, где контент действительно кэшируется. Динамические запросы с Cookie или Cache-Control: private всё равно идут к origin: выигрыш сводится к географическому proximity, но не устраняет latency самого backend.
«React отвечает за скорость сайта»
React — только часть pipeline:
DNS, TCP, TLS: network layer;
TTFB: network + backend;
DB query time: backend/data layer;
LCP: browser + network + server;
INP: browser/main thread.
React предоставляет <Profiler> для измерения rendering performance дерева компонентов — но это один слой из многих, никак не влияющий на время SQL-запроса.
Fullstack в вакансиях 2026 года
В актуальных вакансиях заметны характерные технологические связки. «Обычные подозреваемые» – TypeScript, React, Python, PostgreSQL, CI/CD, Git, Kubernetes. Fullstack JavaScript-позиции: JavaScript, React, TypeScript, Node.js, Next.js, NestJS, Express, PostgreSQL. Senior с .NET-стеком: ASP.NET Core, TypeScript, React, Webpack, MS SQL/PostgreSQL, Docker, docker-compose, Python.
Рынок 2026 года всё меньше выглядит как «я умею React» и всё больше как «я провожу feature от браузера до базы и production-инфраструктуры». Важная оговорка: единого обязательного стека не существует. Python, .NET, Ruby и другие комбинации по-прежнему живут в production-вакансиях — рынок становится полицентричным, а не монолитным.
Stack Overflow Developer Survey 2025 фиксирует отдельно: Docker совершил заметный скачок использования, среди web-фреймворков продолжают лидировать React, Node.js и Next.js, вырос интерес к FastAPI.
Актуально для Middle:
JavaScript/TypeScript;
React, Vue или другой production frontend;
REST/API, SQL, PostgreSQL;
Git, базовый Docker;
понимание HTTP и основ сетей;
debugging через Chrome DevTools;
тестирование, понимание deployment.
Senior — дополнительно:
system design;
performance и observability;
caching, queues;
CI/CD;
database optimization: query plans, индексы, connection pooling;
trade-offs между SSR/CSR/SSG;
способность диагностировать проблему между слоями стека.
Именно последний пункт — ключевой. Senior видит не страницу. Он видит цепочку подсистем, каждая из которых способна добавить следующие 50 мс.
Где закрыть пробелы системно
Три программы подобраны не по принципу «лучший курс», а по соответствию конкретным участкам разобранного пути.
Если раздел про DNS/TLS и диагностику запроса обнаружил пробелы
HTTP, асинхронность, REST API и Chrome DevTools системно покрывает программа «Fullstack-разработчик на Node.js» от Хекслета. По данным каталога Хабр Карьеры, программа включает: Node.js, React, JavaScript, HTTP, REST API, базы данных, Chrome DevTools, SQL, Git/GitHub, Ubuntu. Длительность — 16 месяцев, стоимость — 161 250 ₽.
Ограничение: Node.js/React-стек делает программу менее универсальной для разработчика на Python или .NET; фундаментальные темы могут быть избыточны для опытного специалиста, которому нужно закрыть конкретный пробел.
Подробности о программе — в каталоге Хабр Курсов
Если проблема оказалась в серверной части, а не во frontend
В программе «Профессия Fullstack-разработчик на Python» от Skillfactory есть отдельные блоки по Django, PostgreSQL, Linux, Docker, Nginx, Gunicorn и CI/CD. По данным каталога Хабр Карьеры: 14 месяцев, от 4 829 ₽/мес., 173 844 ₽ при единовременной оплате.
Ограничение: Python/Django-centric стек. Для разработчика в TypeScript/Node.js production — другой технологический маршрут, не прямой аналог первой программы.
За подробностями идем в каталог Хабр Курсов
Если хочется собрать всю цепочку browser → API → DB → deployment в один проект
Программа «Фулстек-разработчик» от Яндекс Практикума последовательно проходит React/TypeScript, Node.js, REST, PostgreSQL, Docker, deployment и security. По данным каталога Хабр Карьеры: 16 месяцев, от 8 287 ₽/мес. или 203 000 ₽ единовременно.
Ограничение: для Middle/Senior с конкретной точечной задачей — например, разобраться только с HTTP/performance — прохождение всей программы избыточно. Ценность выше как систематизация fullstack-базы с нуля, чем как точечный performance bootcamp.
Программа в каталоге Хабр Курсов
FAQ
Правда ли, что весь сайт может загрузиться за 200 мс?
TTFB может составлять 200 мс и менее — особенно при тёплом соединении и cache hit на edge. Но это только время до первого байта ответа. После него браузеру предстоит HTML parsing, CSS, JavaScript, layout, paint и compositing. Для большинства production-сайтов LCP приходится через 1-3 секунды после нажатия Enter.
Где смотреть waterfall на реальном сайте?
Chrome DevTools → вкладка Network. Ключевые данные: Waterfall (визуальная шкала), Timing (DNS, Connect, TLS, Waiting, Receiving), Initiator (что инициировало запрос), connection ID. Дополнительно — Lighthouse для автоматического аудита Core Web Vitals, FCP и LCP.
Что такое N+1 queries и почему это важно знать fullstack-разработчику?
N+1 queries — ситуация, когда приложение делает 1 запрос за списком объектов, а затем N отдельных запросов для каждого. При 100 товарах и 10 мс на запрос — уже секунда задержки только на уровне базы данных. Типичное решение: один запрос с JOIN и грамотным индексом, либо батч-загрузка с WHERE id IN (...). Это проблема не React и не Nginx — это проблема слоя данных, которую видно только при чтении всей цепочки.

