Пользователь смотрит на белый экран и ждёт. Каждая лишняя миллисекунда до первого появления контента — это риск, что он закроет вкладку. Критический путь рендеринга — это минимальная последовательность шагов, которую браузер должен пройти, прежде чем показать что-то пользователю.
Браузер не может отрисовать страницу, пока не построит Render Tree. Render Tree требует и DOM, и CSSOM. Поэтому:
CSS блокирует рендеринг. Пока не загружен и не обработан CSS, браузер не рисует ни одного пикселя. Подключение стилей в конце страницы не ускоряет рендеринг — наоборот, вызывает «мигание» (FOUC, Flash of Unstyled Content).
Синхронный JS блокирует и парсинг HTML, и рендеринг. Когда браузер встречает <script> без атрибутов, он останавливает парсинг HTML, выполняет скрипт и только потом продолжает. Причина: скрипт может вызвать document.write() или изменить DOM, что сделало бы уже построенную часть дерева неактуальной.
Атрибуты defer и async позволяют браузеру загружать скрипты не блокируя парсинг HTML.
`async` — скрипт загружается параллельно, но выполняется немедленно по готовности, прерывая парсинг HTML. Порядок выполнения непредсказуем. Подходит для независимых скриптов: аналитика, счётчики.
`defer` — скрипт загружается параллельно и выполняется после полного парсинга HTML, но до DOMContentLoaded. Порядок выполнения соответствует порядку в HTML. Это предпочтительный вариант для большинства скриптов.
`<link rel="preload">` — говорит браузеру: «загрузи этот ресурс как можно скорее, он понадобится прямо сейчас». Используется для критических ресурсов: главный шрифт, фоновое изображение hero-блока.
`<link rel="prefetch">` — загрузи этот ресурс с низким приоритетом, он понадобится на следующей странице. Браузер сохранит его в кэш.
FCP (First Contentful Paint) — момент, когда браузер впервые отрисовал что-либо: текст, картинку, SVG. Хороший FCP — менее 1.8 секунды.
LCP (Largest Contentful Paint) — момент отрисовки наибольшего видимого элемента: обычно это главное изображение или заголовок. Хороший LCP — менее 2.5 секунды. Это одна из Core Web Vitals и влияет на SEO.
Разница между FCP и LCP показывает, как быстро загружается главный контент после первого появления чего-либо на экране.
<style>media="print" + JavaScript<body> или используй deferpreload для критических ресурсовloading="lazy" для некритическихnavigator.connection даёт информацию о типе соединения: тип (4g, wifi, ethernet), эффективный тип (slow-2g, 2g, 3g, 4g) и ожидаемую задержку. Это позволяет адаптировать загрузку ресурсов под скорость соединения пользователя.
Измерение FCP и LCP через PerformanceObserver, проверка типа соединения
// PerformanceObserver — наблюдает за метриками производительности в реальном времени
// Измеряем FCP (First Contentful Paint)
const fcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries()
entries.forEach(entry => {
console.log(`FCP: ${entry.startTime.toFixed(0)} мс`)
// Хорошо: < 1800 мс, Нужно улучшить: 1800-3000 мс, Плохо: > 3000 мс
const rating = entry.startTime < 1800 ? 'Хорошо' :
entry.startTime < 3000 ? 'Средне' : 'Плохо'
console.log('Оценка FCP:', rating)
})
})
fcpObserver.observe({ type: 'paint', buffered: true })
// Измеряем LCP (Largest Contentful Paint)
const lcpObserver = new PerformanceObserver((list) => {
// LCP обновляется по мере загрузки — берём последнее значение
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
console.log(`LCP: ${lastEntry.startTime.toFixed(0)} мс`)
console.log('LCP элемент:', lastEntry.element?.tagName)
})
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })
// Информация о соединении пользователя
if ('connection' in navigator) {
const conn = navigator.connection
console.log('Тип соединения:', conn.effectiveType) // 4g, 3g, 2g, slow-2g
console.log('Ожидаемая задержка (RTT):', conn.rtt, 'мс')
console.log('Скорость загрузки:', conn.downlink, 'Мбит/с')
// Адаптируем качество под скорость
if (conn.effectiveType === 'slow-2g' || conn.effectiveType === '2g') {
console.log('Медленное соединение — загружаем облегчённые ресурсы')
}
}Пользователь смотрит на белый экран и ждёт. Каждая лишняя миллисекунда до первого появления контента — это риск, что он закроет вкладку. Критический путь рендеринга — это минимальная последовательность шагов, которую браузер должен пройти, прежде чем показать что-то пользователю.
Браузер не может отрисовать страницу, пока не построит Render Tree. Render Tree требует и DOM, и CSSOM. Поэтому:
CSS блокирует рендеринг. Пока не загружен и не обработан CSS, браузер не рисует ни одного пикселя. Подключение стилей в конце страницы не ускоряет рендеринг — наоборот, вызывает «мигание» (FOUC, Flash of Unstyled Content).
Синхронный JS блокирует и парсинг HTML, и рендеринг. Когда браузер встречает <script> без атрибутов, он останавливает парсинг HTML, выполняет скрипт и только потом продолжает. Причина: скрипт может вызвать document.write() или изменить DOM, что сделало бы уже построенную часть дерева неактуальной.
Атрибуты defer и async позволяют браузеру загружать скрипты не блокируя парсинг HTML.
`async` — скрипт загружается параллельно, но выполняется немедленно по готовности, прерывая парсинг HTML. Порядок выполнения непредсказуем. Подходит для независимых скриптов: аналитика, счётчики.
`defer` — скрипт загружается параллельно и выполняется после полного парсинга HTML, но до DOMContentLoaded. Порядок выполнения соответствует порядку в HTML. Это предпочтительный вариант для большинства скриптов.
`<link rel="preload">` — говорит браузеру: «загрузи этот ресурс как можно скорее, он понадобится прямо сейчас». Используется для критических ресурсов: главный шрифт, фоновое изображение hero-блока.
`<link rel="prefetch">` — загрузи этот ресурс с низким приоритетом, он понадобится на следующей странице. Браузер сохранит его в кэш.
FCP (First Contentful Paint) — момент, когда браузер впервые отрисовал что-либо: текст, картинку, SVG. Хороший FCP — менее 1.8 секунды.
LCP (Largest Contentful Paint) — момент отрисовки наибольшего видимого элемента: обычно это главное изображение или заголовок. Хороший LCP — менее 2.5 секунды. Это одна из Core Web Vitals и влияет на SEO.
Разница между FCP и LCP показывает, как быстро загружается главный контент после первого появления чего-либо на экране.
<style>media="print" + JavaScript<body> или используй deferpreload для критических ресурсовloading="lazy" для некритическихnavigator.connection даёт информацию о типе соединения: тип (4g, wifi, ethernet), эффективный тип (slow-2g, 2g, 3g, 4g) и ожидаемую задержку. Это позволяет адаптировать загрузку ресурсов под скорость соединения пользователя.
Измерение FCP и LCP через PerformanceObserver, проверка типа соединения
// PerformanceObserver — наблюдает за метриками производительности в реальном времени
// Измеряем FCP (First Contentful Paint)
const fcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries()
entries.forEach(entry => {
console.log(`FCP: ${entry.startTime.toFixed(0)} мс`)
// Хорошо: < 1800 мс, Нужно улучшить: 1800-3000 мс, Плохо: > 3000 мс
const rating = entry.startTime < 1800 ? 'Хорошо' :
entry.startTime < 3000 ? 'Средне' : 'Плохо'
console.log('Оценка FCP:', rating)
})
})
fcpObserver.observe({ type: 'paint', buffered: true })
// Измеряем LCP (Largest Contentful Paint)
const lcpObserver = new PerformanceObserver((list) => {
// LCP обновляется по мере загрузки — берём последнее значение
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
console.log(`LCP: ${lastEntry.startTime.toFixed(0)} мс`)
console.log('LCP элемент:', lastEntry.element?.tagName)
})
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })
// Информация о соединении пользователя
if ('connection' in navigator) {
const conn = navigator.connection
console.log('Тип соединения:', conn.effectiveType) // 4g, 3g, 2g, slow-2g
console.log('Ожидаемая задержка (RTT):', conn.rtt, 'мс')
console.log('Скорость загрузки:', conn.downlink, 'Мбит/с')
// Адаптируем качество под скорость
if (conn.effectiveType === 'slow-2g' || conn.effectiveType === '2g') {
console.log('Медленное соединение — загружаем облегчённые ресурсы')
}
}Напиши код, который создаёт PerformanceObserver для отслеживания LCP. При каждом обновлении выводи в консоль время LCP и тег элемента. После трёх секунд отключи наблюдатель методом disconnect().
Тип события — "largest-contentful-paint". Время хранится в entry.startTime, тег элемента — в entry.element.tagName. Метод отключения наблюдателя называется disconnect().