Глибокий аналіз Web Performance APIs, від традиційних вимірювань часу до сучасних людино-орієнтованих показників, таких як Core Web Vitals, і як їх поєднати для цілісного бачення продуктивності.
За межами годинника: Поєднання Web Performance APIs з реальним користувацьким досвідом
У цифровій економіці швидкість – це не просто функція; це основа користувацького досвіду. Повільний вебсайт може призвести до розчарування користувачів, збільшення показника відмов і прямого впливу на дохід. Протягом багатьох років розробники покладалися на показники часу, такі як window.onload
, для оцінки продуктивності. Але чи справді швидкий час завантаження дорівнює задоволеному користувачеві? Відповідь часто – ні.
Сторінка може завершити завантаження всіх своїх технічних ресурсів менш ніж за секунду, але відчуватися млявою та непридатною для реальної людини, яка намагається взаємодіяти з нею. Це роз’єднання підкреслює критичну еволюцію у веб-розробці: перехід від вимірювання технічних термінів до кількісної оцінки людського досвіду. Сучасна продуктивність вебсайту – це розповідь про дві перспективи: гранульовані, низькорівневі дані, надані Web Performance APIs, і високорівневі, людино-орієнтовані показники, такі як Google Core Web Vitals.
Цей вичерпний посібник подолає цей розрив. Ми дослідимо потужний набір Web Performance APIs, які діють як наші діагностичні інструменти. Потім ми заглибимось у сучасні показники користувацького досвіду, які розповідають нам, як «відчувається» продуктивність. Найголовніше, ми з’єднаємо крапки, показуючи вам, як використовувати низькорівневі дані про час для діагностики та усунення основних причин поганого користувацького досвіду для вашої глобальної аудиторії.
Основа: Розуміння Web Performance APIs
Web Performance APIs – це набір стандартизованих інтерфейсів браузера, які надають розробникам доступ до дуже детальних і точних даних про час, пов’язаних із навігацією та рендерингом веб-сторінки. Вони є основою вимірювання продуктивності, дозволяючи нам вийти за межі простих секундомірів і зрозуміти складний танець мережевих запитів, аналізу та рендерингу.
Navigation Timing API: Подорож сторінки
Navigation Timing API надає детальну розбивку часу, необхідного для завантаження основного документа. Він фіксує етапи від моменту, коли користувач ініціює навігацію (наприклад, натискання на посилання), до моменту повного завантаження сторінки. Це наш перший і найфундаментальніший погляд на процес завантаження сторінки.
Ви можете отримати доступ до цих даних за допомогою простого виклику JavaScript:
const navigationEntry = performance.getEntriesByType('navigation')[0];
console.log(navigationEntry.toJSON());
Це повертає об’єкт, наповнений мітками часу. Деякі ключові властивості включають:
- fetchStart: Коли браузер починає отримувати документ.
- responseStart: Коли браузер отримує перший байт відповіді від сервера. Час між
fetchStart
іresponseStart
часто називають Time to First Byte (TTFB). - domContentLoadedEventEnd: Коли початковий HTML-документ повністю завантажено та проаналізовано, не чекаючи завершення завантаження таблиць стилів, зображень і вкладених фреймів.
- loadEventEnd: Коли всі ресурси для сторінки (включаючи зображення, CSS тощо) повністю завантажено.
Протягом тривалого часу loadEventEnd
був золотим стандартом. Однак його обмеження є серйозним: він нічого не говорить про те, коли користувач «бачить» значущий вміст або коли він може «взаємодіяти» зі сторінкою. Це технічний етап, а не людський.
Resource Timing API: Деконструкція компонентів
Веб-сторінка рідко буває одним файлом. Це збірка HTML, CSS, JavaScript, зображень, шрифтів і викликів API. Resource Timing API дозволяє перевіряти час мережі для кожного з цих окремих ресурсів.
Це неймовірно потужно для виявлення вузьких місць. Чи велике, неоптимізоване головне зображення з мережі доставки вмісту (CDN) на іншому континенті сповільнює початковий рендеринг? Чи блокує сторонній аналітичний скрипт основний потік? Resource Timing допомагає вам відповісти на ці запитання.
Ви можете отримати список усіх ресурсів, як показано нижче:
const resourceEntries = performance.getEntriesByType('resource');
resourceEntries.forEach(resource => {
if (resource.duration > 200) { // Знайти ресурси, які займали більше 200 мс
console.log(`Повільний ресурс: ${resource.name}, Тривалість: ${resource.duration}мс`);
}
});
Ключові властивості включають name
(URL-адреса ресурсу), initiatorType
(що спричинило завантаження ресурсу, наприклад, «img», «script») і duration
(загальний час, необхідний для його отримання).
User Timing API: Вимірювання логіки вашої програми
Іноді вузьке місце продуктивності полягає не в завантаженні активів, а в самому коді на стороні клієнта. Скільки часу потрібно вашій односторінковій програмі (SPA) для рендерингу складного компонента після отримання даних з API? User Timing API дозволяє створювати власні, специфічні для програми вимірювання.
Він працює з двома основними методами:
- performance.mark(name): Створює іменовану мітку часу в буфері продуктивності.
- performance.measure(name, startMark, endMark): Обчислює тривалість між двома мітками та створює іменоване вимірювання.
Приклад: Вимірювання часу рендерингу компонента списку продуктів.
// Коли ви починаєте отримувати дані
performance.mark('product-list-fetch-start');
fetch('/api/products')
.then(response => response.json())
.then(data => {
// Після отримання, перед рендерингом
performance.mark('product-list-render-start');
renderProductList(data);
// Відразу після завершення рендерингу
performance.mark('product-list-render-end');
// Створити вимірювання
performance.measure(
'Product List Render Time',
'product-list-render-start',
'product-list-render-end'
);
});
Це дає вам точний контроль для вимірювання частин вашої програми, які є найважливішими для робочого процесу користувача.
PerformanceObserver: Сучасний, ефективний підхід
Постійне опитування performance.getEntriesByType()
є неефективним. API PerformanceObserver
надає набагато кращий спосіб прослуховування записів продуктивності. Ви підписуєтесь на певні типи записів, і браузер асинхронно сповіщає вашу функцію зворотного виклику, коли вони записуються. Це рекомендований спосіб збору даних про продуктивність без додавання накладних витрат до вашої програми.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`Entry Type: ${entry.entryType}, Name: ${entry.name}`);
}
});
observer.observe({ entryTypes: ['resource', 'navigation', 'mark', 'measure'] });
Цей спостерігач є ключем до збору не лише традиційних показників, наведених вище, але й сучасних, людино-орієнтованих показників, які ми обговоримо далі.
Перехід до людино-орієнтованості: Core Web Vitals
Знати, що сторінка завантажилася за 2 секунди, корисно, але це не відповідає на важливі запитання: Чи дивився користувач на порожній екран протягом цих 2 секунд? Чи міг він взаємодіяти зі сторінкою, чи вона була заморожена? Чи стрибав вміст несподівано, коли він намагався читати?
Щоб вирішити цю проблему, Google представив Core Web Vitals (CWV), набір показників, розроблених для вимірювання реального користувацького досвіду сторінки за трьома ключовими вимірами: завантаження, інтерактивність і візуальна стабільність.
Largest Contentful Paint (LCP): Вимірювання відчутного завантаження
LCP вимірює час рендерингу найбільшого зображення або текстового блоку, видимого у вікні перегляду. Це чудовий показник того, коли користувач відчуває, що основний вміст сторінки завантажено. Він безпосередньо відповідає на запитання користувача: «Чи корисна ця сторінка?»
- Добре: Менше 2,5 секунд
- Потребує покращення: Від 2,5 до 4,0 секунд
- Погано: Більше 4,0 секунд
На відміну від loadEventEnd
, LCP зосереджується на тому, що користувач бачить першим, що робить його набагато точнішим відображенням сприйнятої швидкості завантаження.
Interaction to Next Paint (INP): Вимірювання швидкості реагування
INP є наступником First Input Delay (FID) і став офіційним Core Web Vital у березні 2024 року. У той час як FID вимірював лише затримку «першої» взаємодії, INP вимірює затримку «всіх» взаємодій користувача (натискання, торкання, натискання клавіш) протягом життєвого циклу сторінки. Він повідомляє про найдовшу взаємодію, ефективно визначаючи найгіршу швидкість реагування, яку відчуває користувач.
INP вимірює весь час від введення користувача до наступного відображення кадру, відображаючи візуальний зворотний зв’язок. Він відповідає на запитання користувача: «Коли я натискаю цю кнопку, сторінка швидко реагує?»
- Добре: Менше 200 мілісекунд
- Потребує покращення: Від 200 мс до 500 мс
- Погано: Більше 500 мс
Високий INP зазвичай викликаний зайнятим основним потоком, де тривалі завдання JavaScript заважають браузеру реагувати на введення користувача.
Cumulative Layout Shift (CLS): Вимірювання візуальної стабільності
CLS вимірює візуальну стабільність сторінки. Він кількісно визначає, наскільки вміст несподівано переміщається по екрану під час процесу завантаження. Високий показник CLS є поширеним джерелом розчарування користувачів, наприклад, коли ви намагаєтеся натиснути кнопку, але над нею завантажується реклама, штовхаючи кнопку вниз і змушуючи вас натиснути на рекламу.
CLS відповідає на запитання користувача: «Чи можу я використовувати цю сторінку, щоб елементи не стрибали по всьому місцю?»
- Добре: Менше 0,1
- Потребує покращення: Від 0,1 до 0,25
- Погано: Більше 0,25
Поширені причини високого CLS включають зображення або iframe без розмірів, веб-шрифти, що завантажуються пізно, або вміст, який динамічно вставляється на сторінку без резервування для нього місця.
Подолання розриву: Використання API для діагностики поганого користувацького досвіду
Тут все зводиться до купи. Core Web Vitals розповідають нам, «що» пережив користувач (наприклад, повільний LCP). Web Performance APIs розповідають нам, «чому» це сталося. Поєднавши їх, ми перетворюємося з простого спостереження за продуктивністю на активну діагностику та виправлення.
Діагностика повільного LCP
Уявіть, що ваш інструмент Real User Monitoring (RUM) повідомляє про поганий LCP у 4,5 секунди для користувачів у певному регіоні. Як це виправити? Вам потрібно розбити час LCP на складові частини.
- Time to First Byte (TTFB): Чи повільно реагує сервер? Використовуйте Navigation Timing API. Тривалість
responseStart - requestStart
дає вам точний TTFB. Якщо це високий показник, проблема на вашому сервері, конфігурації сервера або базі даних, а не на інтерфейсі. - Затримка завантаження ресурсу та час: Чи повільно завантажується сам елемент LCP? Спочатку визначте елемент LCP (наприклад, головне зображення). Ви можете використовувати
PerformanceObserver
для'largest-contentful-paint'
, щоб отримати сам елемент. Потім використовуйте Resource Timing API, щоб знайти запис для URL-адреси цього елемента. Проаналізуйте його часову шкалу: Чи був тривалийconnectStart
доconnectEnd
(повільна мережа)? Чи бувresponseStart
доresponseEnd
довгим (великий розмір файлу)? Чи було затримано йогоfetchStart
, оскільки він був заблокований іншими ресурсами, що блокують рендеринг, як-от CSS або JavaScript? - Затримка рендерингу елемента: Це час після завершення завантаження ресурсу до фактичного відображення на екрані. Це може бути спричинено тим, що основний потік зайнятий іншими завданнями, як-от виконанням великого пакета JavaScript.
Використовуючи Navigation і Resource Timing, ви можете точно визначити, чи спричинено повільний LCP повільним сервером, скриптом, що блокує рендеринг, чи масивним, неоптимізованим зображенням.
Дослідження поганого INP
Ваші користувачі скаржаться, що натискання кнопки «Додати в кошик» відчувається із затримкою. Ваш показник INP знаходиться в діапазоні «Погано». Це майже завжди проблема основного потоку.
- Визначте тривалі завдання: Long Tasks API є вашим основним інструментом тут. Він повідомляє про будь-яке завдання в основному потоці, яке займає більше 50 мс, оскільки все, що довше, ризикує помітною затримкою для користувача. Налаштуйте
PerformanceObserver
для прослуховування записів'longtask'
. - Корелюйте з діями користувача: Тривале завдання є проблемою лише в тому випадку, якщо воно відбувається, коли користувач намагається взаємодіяти. Ви можете корелювати
startTime
події INP (спостерігається черезPerformanceObserver
для типу'event'
) з часом будь-яких тривалих завдань, які відбулися приблизно в той самий час. Це точно показує, яка функція JavaScript заблокувала взаємодію користувача. - Вимірюйте конкретні обробники: Використовуйте User Timing API, щоб отримати ще більшу деталізацію. Обгорніть свої критичні обробники подій (наприклад, обробник «click» для «Додати в кошик») за допомогою
performance.mark()
іperformance.measure()
. Це точно покаже вам, скільки часу потрібно для виконання вашого власного коду і чи є він джерелом тривалого завдання.
Боротьба з високим CLS
Користувачі повідомляють, що текст стрибає, коли вони читають статтю на своїх мобільних пристроях. Ваш показник CLS становить 0,3.
- Спостерігайте за змінами макета: Використовуйте
PerformanceObserver
для прослуховування записів'layout-shift'
. Кожен запис матимеvalue
(його внесок у показник CLS) і списокsources
, які є елементами DOM, що перемістилися. Це говорить вам, «що» перемістилося. - Знайдіть винуватця ресурсу: Наступне питання — «чому» він перемістився. Поширеною причиною є пізнє завантаження ресурсу та виштовхування іншого вмісту вниз. Ви можете корелювати
startTime
записуlayout-shift
з часомresponseEnd
записів з Resource Timing API. Якщо зміна макета відбувається відразу після завершення завантаження рекламного скрипту або великого зображення, ви, ймовірно, знайшли винуватця. - Проактивні рішення: Виправлення часто передбачає надання розмірів для зображень і реклами (
<img width="1000" height="600">
) або резервування місця на сторінці для динамічного вмісту перед його завантаженням. Resource Timing допомагає вам визначити, щодо яких ресурсів вам потрібно бути проактивними.
Практична реалізація: Створення глобальної системи моніторингу
Розуміння цих API – це одне; їх розгортання для моніторингу досвіду вашої глобальної бази користувачів – наступний крок. Це сфера моніторингу реальних користувачів (RUM).
Об’єднання всього за допомогою PerformanceObserver
Ви можете створити один потужний скрипт для збору всіх цих важливих даних. Мета полягає в тому, щоб зібрати показники та їх контекст, не впливаючи на продуктивність, яку ви намагаєтеся виміряти.
Ось концептуальний фрагмент надійної конфігурації спостерігача:
const collectedMetrics = {};
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
collectedMetrics.lcp = entry.startTime;
} else if (entry.entryType === 'layout-shift') {
collectedMetrics.cls = (collectedMetrics.cls || 0) + entry.value;
} else if (entry.entryType === 'event') {
// Це спрощене представлення розрахунку INP
const duration = entry.duration;
if (duration > (collectedMetrics.inp || 0)) {
collectedMetrics.inp = duration;
}
}
// ... і так далі для інших типів записів, таких як 'longtask'
}
});
observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift', 'event', 'longtask'] });
Надійна відправка даних
Після збору даних вам потрібно надіслати їх на аналітичний сервер для зберігання та аналізу. Дуже важливо зробити це, не затримуючи вивантаження сторінок і не втрачаючи дані від користувачів, які швидко закривають свої вкладки.
API navigator.sendBeacon()
ідеально підходить для цього. Він забезпечує надійний, асинхронний спосіб надсилання невеликої кількості даних на сервер, навіть якщо сторінка вивантажується. Він не очікує відповіді, що робить його легким і неблокуючим.
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const payload = JSON.stringify(collectedMetrics);
navigator.sendBeacon('/api/performance-analytics', payload);
}
});
Важливість глобального огляду
Інструменти для лабораторного тестування, такі як Lighthouse, є безцінними, але вони працюють у контрольованому середовищі. Дані RUM, зібрані з цих API, повідомляють вам про правду про те, що відчувають ваші користувачі в різних країнах, мережевих умовах і пристроях.
Під час аналізу даних завжди сегментуйте їх. Ви можете виявити, що:
- Ваш LCP чудовий для користувачів у Північній Америці, але поганий для користувачів в Австралії, оскільки ваш основний сервер зображень розташований у США.
- Ваш INP високий на Android-пристроях середнього класу, які популярні на ринках, що розвиваються, оскільки ваш JavaScript занадто інтенсивний для їх ЦП.
- Ваш CLS є проблемою лише на певних розмірах екрана, де медіа-запит CSS спричиняє неправильне змінення розміру реклами.
Цей рівень сегментованої інформації дозволяє вам визначати пріоритети оптимізації, які матимуть найбільший вплив на вашу фактичну базу користувачів, де б вони не знаходилися.
Висновок: Від вимірювання до майстерності
Світ продуктивності вебсайтів дозрів. Ми перейшли від простих технічних термінів до складного розуміння сприйнятого користувачем досвіду. Подорож включає три ключові етапи:
- Виміряйте досвід: Використовуйте
PerformanceObserver
для збору Core Web Vitals (LCP, INP, CLS). Це говорить вам, «що» відбувається і «як це відчувається» для користувача. - Діагностуйте причину: Використовуйте основні API часу (Navigation, Resource, User, Long Tasks), щоб копати глибше. Це говорить вам, «чому» досвід поганий.
- Дійте з точністю: Використовуйте об’єднані дані для прийняття обґрунтованих, цілеспрямованих оптимізацій, які усувають першопричину проблеми для певних сегментів користувачів.
Опанувавши як високорівневі показники користувача, так і низькорівневі діагностичні API, ви можете створити цілісну стратегію продуктивності. Ви перестаєте здогадуватися і починаєте створювати веб-досвід, який є не просто технічно швидким, а й таким, що відчувається швидким, чуйним і чудовим для кожного користувача, на кожному пристрої, у всьому світі.