Özel metrikler

Herhangi bir web sitesiyle ilgili olarak evrensel olarak ölçebileceğiniz kullanıcı odaklı metriklere sahip olmak büyük önem taşır. Bu metrikler sayesinde:

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

Evrensel metrikler iyi bir temel çizgisi sunar, ancak birçok durumda belirli bir sitenizde tüm deneyimi sunmak için bu metriklerden daha fazlasını ölçmeniz gerekir.

Özel metrikler, site deneyiminizin yalnızca siteniz için geçerli olabilecek yönlerini ölçmenizi sağlar. Örneğin:

  • Tek sayfalık bir uygulamanın (SPA) bir "sayfadan" geçişi ne kadar sürer? başka bir kullanıcıya atanır.
  • Bir sayfanın, giriş yapmış kullanıcılar için veritabanından getirilen verileri görüntülemesinin ne kadar sürdüğü.
  • Sunucu tarafı olarak oluşturulan (SSR) bir uygulamanın hidrasyona uğraması için gereken süre.
  • Geri gelen ziyaretçiler tarafından yüklenen kaynakların önbellek 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ırarak ve her kare arasındaki deltayı hesaplayarak ana iş parçacığının uzun süreli JavaScript görevleri nedeniyle engellenip engellenmediğini belirleyebilirsiniz. Delta, ekranın kare hızından önemli ölçüde daha uzunsa bunu uzun bir görev olarak bildirebilirsiniz. Ancak bu tür saldırılar, gerçekte performansı etkilediği için (örneğin, pili tüketerek) ö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'si

Tarayıcı Desteği

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

Kaynak

Performance Observer API, bu sayfada ele alınan diğer tüm performans API'lerinden veri toplayan ve görüntüleyen mekanizmadır. İyi veriler elde etmek için bu metriğin anlaşılması kritik önem taşır.

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

Bir PerformanceObserver oluşturmak için bu öğeye yeni performans girişleri gönderildiğinde çalıştırılacak bir geri çağırma 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özlemlemek için kullanılabilecek çeşitli giriş türleri listelenmiştir. Ancak yeni tarayıcılarda, statik PerformanceObserver.supportedEntryTypes özelliğini kullanarak hangi giriş türlerinin kullanılabilir olduğunu inceleyebilirsiniz.

Daha önce gerçekleşen girişleri gözlemleyin

Varsayılan olarak PerformanceObserver nesneleri, girişleri yalnızca gerçekleştiği sırada gözlemleyebilir. Bu durum, performans analizi kodunuzu daha yüksek öncelikli kaynakları engellememesi için geç yüklemek istiyorsanız sorunlara yol açabilir.

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

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

Kaçınılması 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â desteklense de yeni girişler yayınlandığında dinleme yapmanıza izin vermediğinden kullanımı önerilmez. Buna ek olarak, birçok yeni API (largest-contentful-paint gibi) performance nesnesi üzerinden kullanıma sunulmamıştır, yalnızca PerformanceObserver üzerinden kullanıma sunulmuştur.

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

Kullanıcı Zamanlaması API'sı

Tarayıcı Desteği

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

Kaynak

User Timing API, Measurement API'sini kullanabilirsiniz. Bu seçenek, zaman alabilir ve daha sonra bu işaretler arasındaki süreyi ölçebilirsiniz.

// 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 yetenekler sunsa da User Timing API'yi kullanmanın performans araçlarıyla iyi entegre edilmesidir. Örneğin, Chrome Geliştirici Araçları, Performans panelindeki Kullanıcı Zamanlaması ölçümlerini görselleştirir ve birçok analiz sağlayıcısı da yaptığınız ölçümleri otomatik olarak izler ve süre verilerini analiz arka uçlarına gönderir.

Kullanıcı Zamanlaması ölçümlerini raporlamak için PerformanceObserver'ı kullanabilir ve measure türündeki girişleri gözlemlemek üzere kaydedebilirsiniz:

// 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});

Uzun Görevler API'sı

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 ne zaman kare hızını veya giriş gecikmesini etkileyecek kadar uzun bir süre boyunca engellendiğini bilmek açısından kullanışlıdır. Bu API, 50 milisaniyeden uzun süren görevleri raporlar.

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, Long Tasks API'nin temelini oluşturur (ör. Etkileşime Kalan Süre (TTI) ve Toplam Engelleme Süresi (TBT)).

Uzun görevlerin ne zaman gerçekleşeceğini belirlemek için PerformanceObserver'ı kullanıp longtask türündeki girişleri gözlemlemek için kayıt yapabilirsiniz:

// 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});

Uzun Animasyon Çerçeveleri API'sı

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 raporda, daha iyi ilişkilendirme ve daha geniş kapsamlı olabilecek sorunlu gecikmeler gibi Long Tasks API'deki bazı eksiklikler ele alınıyor.

Uzun karelerin ne zaman oluşacağını belirlemek için PerformanceObserver'ı kullanıp long-animation-frame türündeki girişleri gözlemlemek üzere kaydedebilirsiniz:

// 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'si

Tarayıcı Desteği

  • Chrome: 77..
  • Kenar: 79..
  • Firefox: Desteklenmez..
  • Safari: desteklenmez..

Kaynak

Largest Contentful Paint (LCP) metriği, en büyük resmin veya metin bloğunun ne zaman ekrana boyandığını bilmekte faydalıdır ancak bazı durumlarda farklı bir öğenin oluşturma süresini ölçmek isteyebilirsiniz.

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'si

Tarayıcı Desteği

  • Chrome: 76..
  • Kenar: 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 kullanılır. Bu API, etkinlik yaşam döngüsü boyunca meydana gelen çeşitli zaman damgalarını gösterir. Örneğin:

  • startTime: Tarayıcının etkinliği aldığı zaman.
  • processingStart: Tarayıcının, etkinlik için etkinlik işleyicileri işlemeye başlayabildiği zaman.
  • processingEnd: Tarayıcının bu etkinlik için etkinlik işleyicilerden başlatılan tüm eşzamanlı kodları yürütmeyi bitirdiği süre.
  • duration: Etkinlik işleyicilerden başlatılan tüm eşzamanlı kodun yürütme işlemini bitirdikten sonra tarayıcının etkinliği aldığı andan sonraki kareyi boyayabilene kadar geçen süre (güvenlik nedenleriyle 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'si

Tarayıcı Desteği

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

Kaynak

Resource Timing API, geliştiricilere belirli bir sayfa için kaynakların nasıl yüklendiği hakkında ayrıntılı bilgi sağlar. API'nin adına rağmen sağladığı bilgiler yalnızca zamanlama verileriyle sınırlı değildir (ancak bu kadar çok şey vardır). Erişebileceğiniz diğer veriler şunlardır:

  • initiatorType: Kaynağın nasıl getirildiğidir (ör. <script> veya <link> etiketinden ya da fetch() çağrısından).
  • nextHopProtocol: kaynağı getirmek için kullanılan protokoldür (ör. h2 veya quic).
  • encodedBodySize/decodedBodySize]: kaynağın kodlanmış veya kodu çözülmüş biçiminde boyutu (sırasıyla)
  • transferSize: Ağ üzerinden gerçekten 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 (önbelleğin yeniden doğrulanması gerekmiyorsa).

Bir önbellek isabet oranı metriğini veya toplam önbelleğe alınmış kaynak boyutu metriğini ölçmek için kaynak zamanlaması girişlerinin transferSize özelliğini kullanabilirsiniz. Bu metrik, kaynak önbelleğe alma stratejinizin tekrar gelen ziyaretçilerin 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 önbellek tarafından karşılanıp karşılanmadığı 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..
  • Kenar: 12..
  • Firefox: 58..
  • Safari: 15..

Kaynak

Gezinme Zamanlama API'si, Resource Timing API'ye benzer ancak yalnızca gezinme isteklerini bildirir. navigation giriş türü, resource giriş türüne de benzer ancak yalnızca gezinme isteklerine özel (DOMContentLoaded ve load etkinliklerinin etkinleşmesi gibi) bazı ek bilgiler içerir.

Pek çok geliştiricinin sunucu yanıt süresini anlamak için izlediği bir metrik (İlk Bayta Kadar Geçen Süre (TTFB)), Navigation Timing API'yi kullanarak mevcuttur. Özellikle de girişin responseStart zaman damgası kullanılır.

// 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ının Service Worker iş parçacığının getirme etkinliklerine müdahale etmeye başlamadan önce başlatılması için geçen 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'si

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 veri aramanın ne kadar sürdüğünü belirtebilirsiniz. Bu, sunucudaki yavaşlığın neden olduğu performans sorunlarını ayıklama konusunda yararlı olabilir.

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

Yanıtlarınızda sunucu zamanlaması verilerini belirtmek için Server-Timing yanıt başlığını kullanabilirsiniz. Bir örnekle açıklayalım.

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'lerinin resource veya 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});