Standart boyama ve yanıt verme hızı metrikleri, ilk sayfa yüklemesinden sonra bir ölçüm boşluğu bırakır:
LargestContentfulPaint(largest-contentful-paint) yalnızca ilk ("tam") doküman yüklemesini ölçer ve kullanıcı sayfayla ilk kez etkileşime girdiğinde girişleri yayınlamayı durdurur.PerformanceEventTimingveevent/ Interaction to Next Paint (INP), bir sonraki kareye kadar (ör. etkin düğme durumu veya yükleme animasyonu) giriş duyarlılığını ölçer ancak sonraki eşzamansız boyamaları (ör. birfetch()çözümlendikten sonra oluşturulan yeni içerik veya istemci tarafı rota geçişi tamamlandıktan sonra) izlemez.- Tek sayfalık uygulamada (SPA) rota değişikliklerini gözlemlemek, çerçeve kodu dışında zor olabilir. Yalnızca URL güncellemelerini izlemek, rota değişiklikleriyle bağlantılı olmayan URL değişikliklerini (ör. yer işareti bağlantısı değişiklikleri, tek bir rota değişikliği için birden fazla "yönlendirme") aşırı raporlayabilir.
InteractionContentfulPaint (interaction-contentful-paint) ve PerformanceSoftNavigation (soft-navigation) performans girişi türleri bu boşluğu doldurur. Yeni zengin içerikli boyamaları ve tek sayfalık uygulama (SPA) rota geçişlerini doğrudan bunları tetikleyen kullanıcı etkileşimiyle ilişkilendirmek için etkileşim nedenselliğini eşzamansız görevlere (fetch, await, setTimeout) yayarlar.
Nasıl uygulanır?
1. Etkileşimlerin tetiklediği içerikli boyamaları gözlemleme
Herhangi bir kullanıcı etkileşimiyle ilişkilendirilebilecek, giderek daha büyük olan, içeriğe sahip boyamaları gözlemlemek için type: 'interaction-contentful-paint' ve buffered: true ile birlikte PerformanceObserver kullanın.
Her InteractionContentfulPaint girişi şunları sağlar:
interactionId: Başlatıcı kullanıcı etkileşiminin benzersiz tanımlayıcısı (PerformanceEventTiming.interactionIdvePerformanceSoftNavigation.interactionIdile eşleşir).startTime: Başlatıcı kullanıcı etkileşiminin başladığı zaman damgası (ilk tam gezinme zamanı kaynağına göre).paintTimevepresentationTime: Oluşturma aşamasının sona erdiği ve boyanan piksellerin ekranda çizildiği zaman.duration: Etkileşimin başlangıcından boyama sunumuna kadar geçen süre (presentationTime - startTime).largestContentfulPaint: Bu etkileşim için şimdiye kadarki en büyük boyanmış öğe hakkında ayrıntılar içeren bir anlık görüntüLargestContentfulPaintnesnesi (element,size,url,id,renderTime,loadTime).
/**
* Observes contentful paints caused by user interactions and invokes a callback
* whenever an interaction produces a larger contentful paint.
*
* @param {(entry: PerformanceEntry) => void} onInteractionPaint
*/
export function observeInteractionPaints(onInteractionPaint) {
// Feature-detect support before calling observe() so unsupported browsers
// do not throw or log console warnings.
if (
typeof PerformanceObserver === 'undefined' ||
!PerformanceObserver.supportedEntryTypes?.includes('interaction-contentful-paint')
) {
return null;
}
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// entry.duration is already calculated as (entry.presentationTime - entry.startTime),
// giving the total time from the user interaction to this contentful paint.
onInteractionPaint(entry);
}
});
// MANDATORY: Pass buffered: true to capture interaction paints that occurred
// before this observer was registered.
observer.observe({ type: 'interaction-contentful-paint', buffered: true });
return observer;
}
2. SPA'daki basit gezinmeler için Largest Contentful Paint'i (LCP) ölçme
Güvenilir bir kullanıcı etkileşimi hem görünür bir URL değişikliğine hem de içerikli boyamaya neden olduğunda tarayıcı tarafından yumuşak gezinme yayınlanır. Her geçişli gezinme için LCP'yi hesaplamak üzere:
buffered: trueile hem'soft-navigation'hem de'interaction-contentful-paint'girişlerini gözlemleyin.- ZORUNLU: Bir
'soft-navigation'girişi alındığındasoftNavEntry.getLargestInteractionContentfulPaint()yöntemini çağırarak ilk LCP adayını ekleyin. Uygulama, URL'yi güncellemeden önce içerik çizdiyse (örneğin, bir görünümü oluşturup ardındanhistory.pushState()çağrısı yaptıysa) bu erkeninteraction-contentful-paintgirişlerisoft-navigationgirişinden önce yayınlanmıştır ve öncekinavigationIddeğerini taşımaya devam eder. - ZORUNLU:
entry.interactionId === softNavEntry.interactionIddeğerini eşleştirerek sonraki'interaction-contentful-paint'girişlerini etkin basit gezinmeyle ilişkilendirin.entry.navigationIddeğerini EŞLEŞTİRMEYİN.interactionIdkullanmak, URL güncellemesinden önce gerçekleşen boyamaları dahil etmenizi ve yeni rotadaki daha sonraki, alakasız etkileşimlerden kaynaklanan boyamaları hariç tutmanızı sağlar.
/**
* Tracks FCP and LCP for each client-side soft navigation and reports finalized
* route metrics when the user navigates to a new route or hides the page.
*
* @param {(report: {
* url: string,
* navigationId: number,
* interactionId: number,
* fcpDuration: number,
* lcpDuration: number | null,
* lcpElement: Element | null,
* lcpSize: number | null
* }) => void} onSoftNavReport
*/
export function trackSoftNavigationLCP(onSoftNavReport) {
const supported =
typeof PerformanceObserver !== 'undefined' &&
PerformanceObserver.supportedEntryTypes?.includes('soft-navigation') &&
PerformanceObserver.supportedEntryTypes?.includes('interaction-contentful-paint');
if (!supported) {
return null;
}
let activeSoftNav = null;
let activeLcpEntry = null;
function finalizeCurrentSoftNav() {
if (!activeSoftNav) return;
onSoftNavReport({
// activeSoftNav.name holds the destination URL of the soft navigation.
url: activeSoftNav.name,
navigationId: activeSoftNav.navigationId,
interactionId: activeSoftNav.interactionId,
// activeSoftNav.duration is (activeSoftNav.presentationTime - activeSoftNav.startTime),
// which represents First Contentful Paint (FCP) relative to interaction start.
fcpDuration: activeSoftNav.duration,
// activeLcpEntry.duration is (activeLcpEntry.presentationTime - activeSoftNav.startTime),
// representing the soft navigation's LCP duration relative to interaction start.
lcpDuration: activeLcpEntry ? activeLcpEntry.duration : null,
lcpElement: activeLcpEntry?.largestContentfulPaint?.element ?? null,
lcpSize: activeLcpEntry?.largestContentfulPaint?.size ?? null,
});
activeSoftNav = null;
activeLcpEntry = null;
}
const softNavObserver = new PerformanceObserver((list) => {
for (const softNavEntry of list.getEntries()) {
// Finalize the previous route's metrics before resetting state for the new route.
finalizeCurrentSoftNav();
activeSoftNav = softNavEntry;
// MANDATORY: Seed the LCP candidate with getLargestInteractionContentfulPaint()
// to capture any attributed contentful paints that occurred before the URL updated.
activeLcpEntry = softNavEntry.getLargestInteractionContentfulPaint();
}
});
const icpObserver = new PerformanceObserver((list) => {
for (const icpEntry of list.getEntries()) {
// MANDATORY: Match by interactionId (not navigationId) so only paints caused
// by the soft navigation's initiating interaction update the route's LCP.
if (activeSoftNav && icpEntry.interactionId === activeSoftNav.interactionId) {
activeLcpEntry = icpEntry;
}
}
});
softNavObserver.observe({ type: 'soft-navigation', buffered: true });
icpObserver.observe({ type: 'interaction-contentful-paint', buffered: true });
// Finalize the active route's LCP when the page is backgrounded or unloaded.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
finalizeCurrentSoftNav();
}
});
return { softNavObserver, icpObserver, finalizeCurrentSoftNav };
}
3. web-vitals ile yumuşak gezinmelerde Core Web Vitals'ı ölçme
Amacınız hem tam hem de kısmi gezinmelerde standart Core Web Vitals (LCP, CLS ve INP) metriklerini bir analiz uç noktasına raporlamaksa her metrik zaman çizelgesini manuel olarak dilimlemek yerine { reportSoftNavs: true } ile web-vitals kitaplığını (v6.0.0+) kullanın.
import { onLCP, onFCP, onCLS, onINP } from 'web-vitals';
function sendToAnalytics(metric) {
// Example-only endpoint; replace with your real telemetry URL.
navigator.sendBeacon(
'/analytics',
JSON.stringify({
name: metric.name,
value: metric.value,
navigationType: metric.navigationType,
navigationURL: metric.navigationURL,
}),
);
}
// Pass { reportSoftNavs: true } to report metrics per soft navigation in addition
// to the initial hard navigation.
onLCP(sendToAnalytics, { reportSoftNavs: true });
onFCP(sendToAnalytics, { reportSoftNavs: true });
onCLS(sendToAnalytics, { reportSoftNavs: true });
onINP(sendToAnalytics, { reportSoftNavs: true });
En iyi uygulamalar
observer.observe()yöntemini çağırmadan öncePerformanceObserver.supportedEntryTypes?.includes(...)kullanarak'interaction-contentful-paint've'soft-navigation'özelliklerini MUTLAKA algılayın.- Analiz kodu eşzamansız olarak başlatılırsa erken girişlerin kaçırılmaması için
'interaction-contentful-paint've'soft-navigation'gözlemlenirken{ buffered: true }GEÇİRİN. - Yeni bir
soft-navigationgirişi işlerkensoftNavEntry.getLargestInteractionContentfulPaint()yöntemini ÇAĞIRIN. Böylece, URL güncellemesinden önce gerçekleşen boyamalar LCP'ye dahil edilir. interaction-contentful-paintgirişlerininavigationIdile değil,interactionIdkullanarak yumuşak gezinmeyle eşleştirin (DO).entry.presentationTimedeğerini doğrudan raporlamak yerine etkileşim boyama gecikmesini ölçmek içinentry.duration(veyaentry.presentationTime - entry.startTime) KULLANIN. TümPerformanceEntryzaman damgaları, yumuşak gezinme başlangıcından değil, ilk sert sayfa yükleme süresi kaynağından ölçülür.- Tarayıcının arabelleği ilk 50 geçiş girişiyle sınırlı olduğundan, uzun süreli tek sayfalık uygulamaları izlemek için
performance.getEntriesByType('soft-navigation')'yi KULLANMAYIN.
Yedek stratejiler
Baseline hedefiniz InteractionContentfulPaint veya PerformanceSoftNavigation'yı desteklemeyen tarayıcılar içeriyorsa bu API'leri Gerçek Kullanıcı İzleme (RUM) için progresif geliştirme olarak değerlendirin:
- Özellik algılama ve kontrollü azalma: Gözlemci kaydını
PerformanceObserver.supportedEntryTypes?.includes('interaction-contentful-paint')vePerformanceObserver.supportedEntryTypes?.includes('soft-navigation')ile koruyun. Desteklenmeyen tarayıcılarda, uygulamanızın hata vermeden çalışması için gözlemcileri kaydetmeyi atlayın. - Standart tam sayfa gezinme gözlemcilerini etkin tutun: Tüm tarayıcılarda standart
'largest-contentful-paint','event've'layout-shift'girişlerini gözlemlemeye devam edin.LargestContentfulPaint, basit gezinme desteğinden bağımsız olarak ilk kullanıcı etkileşiminde kesinleştiğinden, destekleyen tarayıcılarda basit gezinmeleri ölçmek, ilk tam yükleme LCP ölçümlerini değiştirmez veya bozmaz.