Metrik kustom

Ada banyak manfaat dari memiliki metrik yang berfokus pada pengguna yang dapat Anda ukur, secara universal, di situs mana pun. Metrik ini memungkinkan Anda:

  • Memahami pengalaman pengguna nyata dengan web secara keseluruhan.
  • Bandingkan situs Anda dengan situs pesaing.
  • Lacak data yang berguna dan dapat ditindaklanjuti di alat analisis Anda tanpa perlu menulis kode kustom.

Metrik universal menawarkan dasar pengukuran yang baik, tetapi dalam banyak kasus, Anda perlu mengukur lebih dari metrik ini untuk menangkap pengalaman lengkap untuk situs Anda.

Metrik kustom memungkinkan Anda mengukur aspek pengalaman situs yang mungkin hanya berlaku untuk situs Anda, seperti:

  • Waktu yang dibutuhkan aplikasi web satu halaman (SPA) untuk bertransisi dari satu "halaman" ke negara lain.
  • Waktu yang dibutuhkan halaman untuk menampilkan data yang diambil dari database untuk pengguna yang login.
  • Waktu yang diperlukan aplikasi server-side-render (SSR) untuk melakukan hidrasi.
  • Rasio cache ditemukan untuk resource yang dimuat oleh pengunjung yang kembali.
  • Latensi peristiwa klik atau peristiwa keyboard dalam game.

API untuk mengukur metrik kustom

Sebelumnya, developer web belum memiliki banyak API tingkat rendah untuk mengukur performa. Akibatnya, mereka harus melakukan peretasan untuk mengukur apakah suatu situs berperforma baik atau tidak.

Misalnya, Anda dapat menentukan apakah thread utama diblokir karena tugas JavaScript yang berjalan lama dengan menjalankan loop requestAnimationFrame dan menghitung delta di antara setiap frame. Jika delta secara signifikan lebih panjang dari kecepatan frame layar, Anda dapat melaporkannya sebagai tugas yang panjang. Namun, peretasan semacam itu tidak disarankan karena akan memengaruhi performanya sendiri (misalnya, dengan menghabiskan baterai).

Aturan pertama pengukuran kinerja yang efektif adalah memastikan bahwa teknik pengukuran kinerja Anda tidak menyebabkan masalah kinerja itu sendiri. Jadi untuk setiap metrik kustom yang Anda ukur di situs, sebaiknya gunakan salah satu API berikut jika memungkinkan.

API Pengamat Performa

Dukungan Browser

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

Sumber

Performance Observer API adalah mekanisme yang mengumpulkan dan menampilkan data dari semua API performa lain yang dibahas di halaman ini. Memahami hal tersebut sangat penting untuk mendapatkan data yang baik.

Anda dapat menggunakan PerformanceObserver untuk berlangganan peristiwa terkait performa secara pasif. Hal ini memungkinkan callback API diaktifkan selama periode tidak ada aktivitas, yang berarti callback ini biasanya tidak akan mengganggu performa halaman.

Untuk membuat PerformanceObserver, teruskan callback untuk dijalankan setiap kali entri performa baru dikirim. Kemudian, Anda memberi tahu observer jenis entri yang perlu diproses menggunakan metode observe():

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

Bagian berikut mencantumkan semua jenis entri yang tersedia untuk diamati, tetapi di browser yang lebih baru, Anda dapat memeriksa jenis entri yang tersedia melalui properti PerformanceObserver.supportedEntryTypes statis.

Mengamati entri yang sudah terjadi

Secara default, objek PerformanceObserver hanya dapat mengamati entri saat terjadi. Hal ini dapat menyebabkan masalah jika Anda ingin memuat kode analisis performa secara lambat agar tidak memblokir resource dengan prioritas lebih tinggi.

Untuk mendapatkan entri historis (setelah entri terjadi), setel tanda buffered ke true saat Anda memanggil observe(). Browser akan menyertakan entri historis dari buffer entri performa saat pertama kali callback PerformanceObserver dipanggil, hingga ukuran buffer maksimum untuk jenis tersebut.

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

API performa lama yang harus dihindari

Sebelum Performance Observer API, developer dapat mengakses entri performa menggunakan tiga metode berikut yang ditentukan pada objek performance:

Meskipun API ini masih didukung, penggunaannya tidak direkomendasikan karena tidak memungkinkan Anda memproses saat entri baru dimunculkan. Selain itu, banyak API baru (seperti largest-contentful-paint) tidak ditampilkan melalui objek performance, tetapi hanya diekspos melalui PerformanceObserver.

Kecuali jika Anda secara khusus memerlukan kompatibilitas dengan Internet Explorer, sebaiknya hindari metode ini di kode Anda dan gunakan PerformanceObserver untuk ke depannya.

API Waktu Pengguna

Dukungan Browser

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

Sumber

User Timing API bersifat umum Measurement API untuk metrik berbasis waktu. Ini memungkinkan Anda secara bebas menandai poin di waktu dan kemudian mengukur durasinya di antara tanda tersebut.

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

Meskipun API seperti Date.now() atau performance.now() memberi Anda kemampuan yang serupa, manfaat penggunaan User Timing API adalah terintegrasi dengan baik dengan alat performa. Misalnya, Chrome DevTools memvisualisasikan pengukuran Waktu Pengguna di panel Performa, dan banyak penyedia analisis juga akan otomatis melacak pengukuran apa pun yang Anda lakukan dan mengirim data durasi ke backend analisisnya.

Untuk melaporkan pengukuran Waktu Pengguna, Anda dapat menggunakan PerformanceObserver dan mendaftar untuk mengamati entri jenis measure:

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

API Tugas Panjang

Dukungan Browser

  • Chrome: 58.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Long Tasks API berguna untuk mengetahui kapan thread utama browser diblokir cukup lama untuk memengaruhi kecepatan frame atau latensi input. API akan melaporkan tugas apa pun yang dijalankan selama lebih dari 50 milidetik.

Kapan pun Anda perlu menjalankan kode yang mahal, atau memuat dan mengeksekusi skrip besar, akan berguna untuk melacak apakah kode itu memblokir thread utama. Faktanya, banyak metrik dengan tingkat lebih tinggi yang dibuat menggunakan Long Tasks API itu sendiri (seperti Time to Interactive (TTI) dan Total Blocking Time (TBT)).

Untuk menentukan kapan tugas yang berjalan lama terjadi, Anda dapat menggunakan PerformanceObserver dan mendaftar untuk mengamati entri jenis longtask:

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

Dukungan Browser

  • Chrome: 123.
  • Edge: 123.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Long Animation Frames API adalah iterasi baru dari Long Tasks API yang menampilkan frame panjang—bukan tugas panjang—yang berdurasi lebih dari 50 milidetik. Tindakan ini akan mengatasi beberapa kelemahan Long Tasks API, termasuk atribusi yang lebih baik dan cakupan penundaan yang lebih luas yang berpotensi menimbulkan masalah.

Untuk menentukan kapan frame panjang terjadi, Anda dapat menggunakan PerformanceObserver dan mendaftar untuk mengamati entri jenis long-animation-frame:

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

API Waktu Elemen

Dukungan Browser

  • Chrome: 77.
  • Edge: 79.
  • Firefox: tidak didukung.
  • Safari: tidak didukung.

Sumber

Metrik Largest Contentful Paint (LCP) berguna untuk mengetahui kapan gambar atau blok teks terbesar digambar ke layar, tetapi dalam beberapa kasus Anda ingin mengukur waktu render elemen yang berbeda.

Untuk kasus ini, gunakan Element Timing API. LCP API sebenarnya dibuat di atas Element Timing API dan menambahkan pelaporan otomatis dari elemen konten terbesar, tetapi Anda juga dapat melaporkan elemen lain dengan secara eksplisit menambahkan atribut elementtiming ke elemen tersebut, dan mendaftarkan PerformanceObserver untuk mengamati jenis entri element.

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

API Waktu Peristiwa

Dukungan Browser

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 89.
  • Safari: tidak didukung.

Sumber

Metrik Interaction to Next Paint (INP) menilai responsivitas halaman secara keseluruhan dengan mengamati semua interaksi klik, ketukan, dan keyboard selama masa aktif halaman. INP halaman paling sering merupakan interaksi yang memerlukan waktu paling lama untuk diselesaikan, mulai dari saat pengguna memulai interaksi, hingga saat browser menggambar frame berikutnya yang menunjukkan hasil visual dari input pengguna.

Metrik INP dimungkinkan oleh Event Timing API. API ini mengekspos sejumlah stempel waktu yang terjadi selama siklus proses peristiwa, termasuk:

  • startTime: waktu saat browser menerima peristiwa.
  • processingStart: waktu saat browser dapat mulai memproses pengendali peristiwa untuk peristiwa tersebut.
  • processingEnd: waktu saat browser selesai mengeksekusi semua kode sinkron yang dimulai dari pengendali peristiwa untuk peristiwa ini.
  • duration: waktu (dibulatkan menjadi 8 milidetik untuk alasan keamanan) antara saat browser menerima peristiwa hingga dapat menggambar frame berikutnya setelah selesai mengeksekusi semua kode sinkron yang dimulai dari pengendali peristiwa.

Contoh berikut menunjukkan cara menggunakan nilai ini untuk membuat pengukuran kustom:

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

API Resource Timing

Dukungan Browser

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

Sumber

Resource Timing API memberikan insight mendetail kepada developer tentang cara resource untuk halaman tertentu dimuat. Terlepas dari nama API ini, informasi yang diberikannya tidak hanya terbatas pada data waktu (meskipun ada banyak sekali). Data lain yang dapat Anda akses meliputi:

  • initiatorType: cara resource diambil: seperti dari tag <script> atau <link>, atau dari panggilan fetch().
  • nextHopProtocol: protokol yang digunakan untuk mengambil resource, seperti h2 atau quic.
  • encodedBodySize/decodedBodySize]: ukuran resource dalam bentuk yang dienkode atau didekode (masing-masing)
  • transferSize: ukuran resource yang benar-benar ditransfer melalui jaringan. Jika resource dipenuhi oleh cache, nilai ini bisa jauh lebih kecil daripada encodedBodySize, dan dalam beberapa kasus bisa nol (jika validasi ulang cache tidak diperlukan).

Anda dapat menggunakan properti transferSize dari entri waktu resource untuk mengukur metrik rasio hit cache atau metrik total ukuran resource yang di-cache, yang dapat berguna dalam memahami pengaruh strategi penyimpanan dalam cache resource Anda terhadap performa untuk pengunjung berulang.

Contoh berikut mencatat semua resource yang diminta oleh halaman dan menunjukkan apakah setiap resource dipenuhi oleh cache atau tidak.

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

Dukungan Browser

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

Sumber

Navigation Timing API mirip dengan Resource Timing API, tetapi hanya melaporkan permintaan navigasi. Jenis entri navigation juga mirip dengan jenis entri resource, tetapi berisi beberapa informasi tambahan khusus untuk permintaan navigasi saja (seperti saat peristiwa DOMContentLoaded dan load diaktifkan).

Satu metrik yang dilacak banyak developer untuk memahami waktu respons server (Time to First Byte (TTFB)) tersedia menggunakan Navigation Timing API—khususnya stempel waktu responseStart entri.

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

Metrik lain yang menjadi perhatian developer yang menggunakan pekerja layanan adalah waktu startup pekerja layanan untuk permintaan navigasi. Ini adalah jumlah waktu yang diperlukan browser untuk memulai thread pekerja layanan sebelum dapat mulai mencegat peristiwa pengambilan.

Waktu startup pekerja layanan untuk permintaan navigasi tertentu dapat ditentukan dari delta antara entry.responseStart dan entry.workerStart.

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

API Waktu Server

Dukungan Browser

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

Sumber

Server Timing API memungkinkan Anda meneruskan data waktu khusus permintaan dari server Anda ke browser melalui header respons. Misalnya, Anda dapat menunjukkan waktu yang diperlukan untuk mencari data dalam database untuk permintaan tertentu—yang dapat berguna dalam proses debug masalah performa yang disebabkan oleh kelambatan di server.

Untuk developer yang menggunakan penyedia analisis pihak ketiga, Server Timing API adalah satu-satunya cara untuk menghubungkan data performa server dengan metrik bisnis lain yang mungkin diukur oleh alat analisis ini.

Untuk menentukan data waktu server dalam respons, Anda dapat menggunakan header respons Server-Timing. Berikut contohnya.

HTTP/1.1 200 OK

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

Kemudian, dari halaman, Anda dapat membaca data ini pada entri resource atau navigation dari Resource Timing API dan Navigation Timing API.

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