Özel metrikler

Herhangi bir web sitesinde evrensel olarak ölçebileceğiniz kullanıcı odaklı metriklere sahip olmak çok değerlidir. Bu metrikler sayesinde şunları yapabilirsiniz:

  • Gerçek kullanıcıların web'i bir bütün olarak nasıl deneyimlediğini anlayın.
  • Sitenizi bir rakibinizin sitesiyle karşılaştırın.
  • Özel kod yazmanıza gerek kalmadan analiz araçlarınızda faydalı ve işlem yapılabilir verileri izleyin.

Evrensel metrikler iyi bir referans noktası sunar ancak çoğu durumda, belirli bir sitenizin deneyimini tam olarak yakalamak için bu metriklerden daha fazlasını ölçmeniz gerekir.

Özel metrikler, sitenizdeki deneyimin yalnızca siteniz için geçerli olabilecek yönlerini ölçmenize olanak tanır. Örneğin:

  • Tek sayfalık bir uygulamanın (SPA) bir "sayfada"n diğerine geçiş yapması için geçen süre.
  • Bir sayfanın, oturum açmış kullanıcılar için veritabanından alınan verileri göstermesi ne kadar sürer?
  • Sunucu tarafında oluşturulan (SSR) bir uygulamanın etkinleştirilmesi için gereken süre.
  • Geri gelen ziyaretçiler tarafından yüklenen kaynakların önbelleğe isabet oranı.
  • Bir oyundaki tıklama veya klavye etkinliklerinin etkinlik gecikmesi.

Özel metrikleri ölçmek için API'ler

Geçmişte web geliştiricileri, performansı ölçecek çok sayıda alt düzey API'ye sahip değildi. Bunun sonucunda, bir sitenin iyi performans gösterip göstermediğini ölçmek için saldırılara başvurmak zorundaydılar.

Örneğin, bir requestAnimationFrame döngüsü çalıştırıp her kare arasındaki farkı hesaplayarak ana iş parçacığının uzun süre çalışan JavaScript görevleri nedeniyle engellenip engellenmediğini belirlemek mümkündür. Delta, ekranın kare hızından çok daha uzunsa bunu uzun görev olarak bildirebilirsiniz. Ancak bu tür hilelerin performansı etkilediği (ör. pili tüketerek) için önerilmez.

Etkili performans ölçümünün ilk kuralı, performans ölçüm tekniklerinizin performans sorunlarına neden olmadığından emin olmaktır. Bu nedenle, sitenizde ölçtüğünüz özel metrikler için mümkünse aşağıdaki API'lerden birini kullanmanız önerilir.

Performance Observer API

Tarayıcı desteği

  • Chrome: 52.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 11.

Kaynak

Performans Gözlemleyici API'si, bu sayfada açıklanan diğer tüm performans API'lerinden gelen verileri toplayıp görüntüleyen mekanizmadır. İyi veriler elde etmek için bu konuyu anlamak çok önemlidir.

Performansla ilgili etkinliklere pasif olarak abone olmak için PerformanceObserver değerini kullanabilirsiniz. Bu sayede API geri çağırmaları boşta kalma sürelerinde etkinleşir, yani genellikle sayfa performansını etkilemezler.

PerformanceObserver oluşturmak için yeni performans girişleri gönderildiğinde çalıştırılacak bir geri çağırma işlevi iletin. Daha sonra, observe() yöntemini kullanarak gözlemciye ne tür girişler dinlemesi gerektiğini söylersiniz:

const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

po.observe({type: 'some-entry-type'});

Aşağıdaki bölümlerde, gözlemlenebilir tüm giriş türleri listelenmektedir. Ancak yeni tarayıcılarda, statik PerformanceObserver.supportedEntryTypes mülkü aracılığıyla hangi giriş türlerinin kullanılabileceğini inceleyebilirsiniz.

Geçmişte gerçekleşen girişleri gözlemleme

Varsayılan olarak PerformanceObserver nesneleri, girişleri yalnızca gerçekleştiği sırada gözlemleyebilir. Bu durum, performans analizleri kodunuzu daha yüksek öncelikli kaynakları engellememesi için yavaş yüklemek isterseniz sorunlara neden olabilir.

Geçmiş girişleri almak için (gerçekleştikten sonra) observe() işlevini çağırırken buffered işaretini true olarak ayarlayın. Tarayıcı, PerformanceObserver geri çağırma işleviniz ilk kez çağrıldığında performans giriş arabelleğindeki geçmiş girişleri bu tür için maksimum arabellek boyutuna kadar dahil eder.

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

Kullanılmaması gereken eski performans API'leri

Performance Observer API'den önce geliştiriciler, performance nesnesinde tanımlanan aşağıdaki üç yöntemi kullanarak performans girişlerine erişebiliyordu:

Bu API'ler hâlâ destekleniyor olsa da yeni girişler yayınlandığında dinlemenize izin vermedikleri için kullanılmaları önerilmez. Ayrıca, birçok yeni API (largest-contentful-paint gibi) performance nesnesi üzerinden değil, yalnızca PerformanceObserver üzerinden gösterilir.

Özellikle Internet Explorer ile uyumluluğa ihtiyaç duymadığınız sürece, kodunuzda bu yöntemlerden kaçınmanız ve gelecekte PerformanceObserver kullanmanız en iyisidir.

User Timing API

Tarayıcı desteği

  • Chrome: 28.
  • Edge: 12.
  • Firefox: 38.
  • Safari: 11.

Kaynak

User Timing API, zamana dayalı metrikler için genel amaçlı bir ölçüm API'sidir. Bu, noktaları rastgele işaretlemenizi ve daha sonra bu işaretler arasındaki süreyi ölçmenizi sağlar.

// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();

// Record the time immediately after running a task.
performance.mark('myTask:end');

// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');

Date.now() veya performance.now() gibi API'ler size benzer özellikler sunsa da User Timing API'yi kullanmanın avantajı, performans araçlarıyla iyi entegre olmasıdır. Örneğin, Chrome DevTools Performans panelinde kullanıcı zamanlama ölçümlerini görselleştirir. Ayrıca birçok analiz sağlayıcı, yaptığınız tüm ölçümleri otomatik olarak izler ve süre verilerini kendi analiz arka uçlarına gönderir.

Kullanıcı zamanlaması ölçümlerini bildirmek için PerformanceObserver'ı kullanabilir ve measure türündeki girişleri gözlemlemek için kaydolabilirsiniz:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});

Long Tasks API

Tarayıcı desteği

  • Chrome: 58.
  • Kenar: 79.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

Long Tasks API, tarayıcının ana iş parçacığının kare hızını veya giriş gecikmesini etkileyecek kadar uzun süre engellendiğini öğrenmek için yararlıdır. API, 50 milisaniyeden uzun süren tüm görevleri bildirir.

Pahalı kodlar çalıştırmanız veya büyük komut dosyaları yükleyip yürütmeniz gerektiğinde, bu kodun ana iş parçacığını engelleyip engellemediğini izlemek faydalıdır. Aslında, birçok üst düzey metrik (ör. Etkileşime Hazır Olma Süresi (TTI) ve Toplam Engelleme Süresi (TBT)) Long Tasks API'nin üzerine inşa edilmiştir.

Uzun görevlerin ne zaman gerçekleştiğini belirlemek için PerformanceObserver'ı kullanabilir ve longtask türündeki girişleri gözlemlemek için kaydolun:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});

Long Animation Frames API

Tarayıcı desteği

  • Chrome: 123.
  • Kenar: 123.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

Long Animation Frames API, Long Tasks API'nin 50 milisaniyeden uzun süren uzun görevler yerine uzun karelere bakan yeni bir sürümüdür. Bu sayede, daha iyi ilişkilendirme ve soruna yol açabilecek gecikmeler için daha geniş bir kapsam da dahil olmak üzere Long Tasks API'nin bazı eksiklikleri giderilir.

Uzun karelerin ne zaman gerçekleştiğini belirlemek için PerformanceObserver'ı kullanabilir ve long-animation-frame türündeki girişleri gözlemlemek için kaydolabilirsiniz:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});

Element Timing API

Tarayıcı desteği

  • Chrome: 77.
  • Edge: 79.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

Largest Contentful Paint (LCP) metriği, en büyük resmin veya metin bloğunun ekrana ne zaman çizildiğini öğrenmek için kullanışlıdır ancak bazı durumlarda farklı bir öğenin oluşturma süresini ölçmek istersiniz.

Bu durumlarda Element Timing API'yi kullanın. LCP API, aslında Element Timing API'yi temel almakta ve en büyük zengin içerikli öğenin otomatik olarak raporlanmasını ekler. Bununla birlikte, diğer öğeler için açıkça elementtiming özelliğini ekleyerek ve element giriş türünü gözlemlemek için bir PerformanceObserver kaydederek diğer öğeler hakkında da rapor oluşturabilirsiniz.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->

<script>
  const po = new PerformanceObserver((entryList) => {
    for (const entry of entryList.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });

  // Start listening for `element` entries to be dispatched.
  po.observe({type: 'element', buffered: true});
</script>

Event Timing API

Tarayıcı desteği

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 89.
  • Safari: desteklenmez.

Kaynak

Sonraki Boyamayla Etkileşim (INP) metriği, bir sayfanın kullanım süresi boyunca gerçekleşen tüm tıklama, dokunma ve klavye etkileşimlerini gözlemleyerek genel sayfa duyarlılığını değerlendirir. Bir sayfanın INP'si genellikle kullanıcının etkileşimi başlattığı andan tarayıcının kullanıcı girişinin görsel sonucunu gösteren bir sonraki kareyi boyadığı zamana kadar tamamlanması en uzun süren etkileşimdir.

INP metriği, Event Timing API tarafından sağlanır. Bu API, etkinlik yaşam döngüsü sırasında gerçekleşen bir dizi zaman damgasını gösterir. Örneğin:

  • startTime: Tarayıcının etkinliği aldığı zaman.
  • processingStart: Tarayıcının etkinlik için etkinlik işleyicilerini işlemeye başlayabileceği zaman.
  • processingEnd: Tarayıcının, bu etkinlik için etkinlik işleyicilerden başlatılan tüm eşzamanlı kodu yürütmeyi tamamladığı zaman.
  • duration: Tarayıcının etkinliği aldığı andan, etkinlik işleyicilerden başlatılan tüm senkronize kodun yürütülmesini tamamladıktan sonra bir sonraki kareyi boyayabildiği ana kadar geçen süre (güvenlik nedeniyle 8 milisaniyeye yuvarlanır).

Aşağıdaki örnekte, özel ölçümler oluşturmak için bu değerlerin nasıl kullanılacağı gösterilmektedir:

const po = new PerformanceObserver((entryList) => {
  // Get the last interaction observed:
  const entries = Array.from(entryList.getEntries()).forEach((entry) => {
    // Get various bits of interaction data:
    const inputDelay = entry.processingStart - entry.startTime;
    const processingTime = entry.processingEnd - entry.processingStart;
    const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
    const duration = entry.duration;
    const eventType = entry.name;
    const target = entry.target || "(not set)"

    console.log("----- INTERACTION -----");
    console.log(`Input delay (ms): ${inputDelay}`);
    console.log(`Event handler processing time (ms): ${processingTime}`);
    console.log(`Presentation delay (ms): ${presentationDelay}`);
    console.log(`Total event duration (ms): ${duration}`);
    console.log(`Event type: ${eventType}`);
    console.log(target);
  });
});

// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});

Resource Timing API

Tarayıcı desteği

  • Chrome: 29.
  • Edge: 12.
  • Firefox: 35.
  • Safari: 11.

Kaynak

Resource Timing API, geliştiricilere belirli bir sayfanın kaynakları nasıl yüklendiğini ayrıntılı olarak gösterir. API'nin adına rağmen sağladığı bilgiler yalnızca zamanlama verileriyle sınırlı değildir (bununla birlikte çok sayıda zamanlama verisi vardır). Erişebileceğiniz diğer veriler şunlardır:

  • initiatorType: Kaynağın getirilme şekli: <script> veya <link> etiketi ya da fetch() çağrısı gibi.
  • nextHopProtocol: Kaynağı getirmek için kullanılan protokol (ör. h2 veya quic).
  • encodedBodySize/decodedBodySize]: kaynağın kodlanmış veya kodu çözülmüş biçiminde boyutu (sırasıyla)
  • transferSize: Ağ üzerinden gerçekte aktarılan kaynağın boyutu. Kaynaklar önbellek tarafından karşılandığında bu değer encodedBodySize değerinden çok daha küçük olabilir ve bazı durumlarda sıfır olabilir (önbellek yeniden doğrulaması gerekmiyorsa).

Önbellek isabet oranı metriğini veya önbelleğe alınan toplam kaynak boyutu metriğini ölçmek için kaynak zamanlama girişlerinin transferSize mülkünü kullanabilirsiniz. Bu metrik, kaynak önbelleğe alma stratejinizin tekrar ziyaret eden kullanıcıların performansını nasıl etkilediğini anlamanıza yardımcı olabilir.

Aşağıdaki örnekte, sayfa tarafından istenen tüm kaynaklar günlüğe kaydedilir ve her bir kaynağın önbelleğe alınıp alınmadığı belirtilir.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // If transferSize is 0, the resource was fulfilled using the cache.
    console.log(entry.name, entry.transferSize === 0);
  }
});

// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});

Tarayıcı desteği

  • Chrome: 57.
  • Edge: 12.
  • Firefox: 58.
  • Safari: 15.

Kaynak

Navigation Timing API, Resource Timing API'ye benzer ancak yalnızca gezinme isteklerini raporlar. navigation giriş türü de resource giriş türüne benzer ancak yalnızca gezinme isteklerine özgü bazı ek bilgiler içerir (ör. DOMContentLoaded ve load etkinliklerinin tetiklendiği durumlar).

Birçok geliştiricinin sunucu yanıt süresini (ilk bayt zamanı (TTFB)) anlamak için izlediği bir metrik, Gezinme Zamanlaması API'si (özellikle de girişinin responseStart zaman damgası) kullanılarak kullanılabilir.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // If transferSize is 0, the resource was fulfilled using the cache.
    console.log('Time to first byte', entry.responseStart);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});

Service Worker'ı kullanan geliştiricilerin önemseyebileceği bir diğer metrik de gezinme istekleri için Service Worker başlatma süresidir. Bu, tarayıcı tarafından getirme etkinliklerini durdurmaya başlamadan önce hizmet çalışanı iş parçacığının başlatılması için gereken süredir.

Belirli bir gezinme isteği için hizmet çalışanı başlatma süresi, entry.responseStart ile entry.workerStart arasındaki deltadan belirlenebilir.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('Service Worker startup time:',
        entry.responseStart - entry.workerStart);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});

Server Timing API

Tarayıcı desteği

  • Chrome: 65.
  • Kenar: 79.
  • Firefox: 61.
  • Safari: 16.4.

Kaynak

Server Timing API, isteğe özel zamanlama verilerini sunucunuzdan yanıt başlıkları aracılığıyla tarayıcınıza iletmenizi sağlar. Örneğin, belirli bir istek için veritabanında verilerin aranmasının ne kadar sürdüğünü belirtebilirsiniz. Bu, sunucudaki yavaşlıktan kaynaklanan performans sorunlarını gidermede yararlı olabilir.

Üçüncü taraf analiz sağlayıcıları kullanan geliştiriciler için sunucu performansı verilerini bu analiz araçlarının ölçebileceği diğer işletme metrikleriyle ilişkilendirmenin tek yolu Sunucu Zamanlaması API'sidir.

Yanıtlarınızda sunucu zamanlama verilerini belirtmek için Server-Timing yanıt üst bilgisini kullanabilirsiniz. Örneğin,

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

Ardından, sayfalarınızdan bu verileri Resource Timing ve Navigation Timing API'lerindeki hem resource hem de navigation girişlerinde okuyabilirsiniz.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Logs all server timing data for this response
    console.log('Server Timing', entry.serverTiming);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});