FID i INP - optymalizacja interaktywności strony
FID (First Input Delay) i jego następca INP (Interaction to Next Paint) mierzą responsywność strony na interakcje użytkownika. Od marca 2024 INP zastąpił FID w Core Web Vitals. Dowiedz się jak zoptymalizować oba wskaźniki.
Krótka odpowiedź
FID vs INP - różnice i progi
First Input Delay (FID):
- Mierzy czas od pierwszej interakcji (klik, tap) do reakcji przeglądarki
- Tylko pierwsza interakcja
- Dobry: ≤ 100ms
- Wymaga poprawy: 100-300ms
- Słaby: > 300ms
Interaction to Next Paint (INP):
- Mierzy opóźnienie wszystkich interakcji podczas wizyty
- Raportuje 75. percentyl (lub najgorsza interakcja dla <50 interakcji)
- Dobry: ≤ 200ms
- Wymaga poprawy: 200-500ms
- Słaby: > 500ms
Dlaczego zmiana FID → INP:
FID mierzył tylko pierwszą interakcję, która często jest szybka. Użytkownicy doświadczają wolnych interakcji później - np. przy scrollowaniu galerii, klikaniu w menu. INP lepiej odzwierciedla rzeczywiste doświadczenie.
Przyczyny słabego FID/INP
1. Długie taski JavaScript:
Każdy task JS >50ms blokuje main thread i opóźnia reakcję na interakcje.
Przykłady:
- Parsowanie dużych bibliotek (React, Vue, Angular)
- Złożone obliczenia
- Synchroniczne operacje DOM
- Third-party scripts (analytics, reklamy, chat)
2. Hydration w SPA:
React/Vue/Angular muszą "hydratować" HTML - podłączyć event handlery. Strona wygląda interaktywna, ale nie reaguje.
3. Event handlery:
Złożone funkcje uruchamiane przy każdym kliknięciu, scrollu, input.
4. Memory leaks:
Narastająca pamięć spowalnia przeglądarkę z czasem.
5. Layout thrashing:
Czytanie i pisanie do DOM na przemian wymusza wielokrotne przeliczanie layoutu.
Optymalizacja JavaScript
Code splitting:
```javascript
// Zamiast importować wszystko
import { heavyFunction } from './utils';
// Dynamiczny import
const { heavyFunction } = await import('./utils');
```
Rozbijanie długich tasków:
```javascript
// Źle - blokuje na 200ms
for (let i = 0; i < 10000; i++) { expensiveOperation(i); }
// Dobrze - oddaje kontrolę przeglądarce
function processChunk(items, index = 0) {
const chunk = items.slice(index, index + 100);
chunk.forEach(expensiveOperation);
if (index + 100 < items.length) {
requestIdleCallback(() => processChunk(items, index + 100));
}
}
```
Web Workers:
Przenieś ciężkie obliczenia do Worker - nie blokuje main thread.
Debounce/throttle:
```javascript
// Scroll handler co 100ms zamiast przy każdym pixelu
window.addEventListener('scroll', throttle(handleScroll, 100));
```
Lazy loading third-party:
Ładuj chat, analytics, reklamy po interakcji lub po 3-5 sekundach.
Diagnoza i monitoring
Chrome DevTools > Performance:
1. Nagraj interakcję ze stroną
2. Szukaj "Long Task" (żółte paski >50ms)
3. Kliknij, żeby zobaczyć call stack
4. Znajdź funkcję odpowiedzialną za blokowanie
Lighthouse:
- Metryka TBT (Total Blocking Time) koreluje z FID/INP
- Sekcja "Avoid long main-thread tasks"
Real User Monitoring (RUM):
```javascript
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name === 'first-input') {
console.log('FID:', entry.processingStart - entry.startTime);
}
}
}).observe({type: 'first-input', buffered: true});
```
Chrome Web Vitals Extension:
Pokazuje INP w czasie rzeczywistym podczas przeglądania strony.
Search Console:
Raport Core Web Vitals z danymi terenowymi - rzeczywiste INP użytkowników.