Metrik kustom

Memiliki metrik universal yang berpusat pada pengguna yang dapat Anda ukur di situs mana pun dapat sangat membantu dalam memahami pengalaman pengguna Anda di web, dan dalam membandingkan situs Anda dengan situs pesaing. Namun, dalam banyak kasus, Anda perlu mengukur lebih dari sekadar metrik universal untuk menangkap pengalaman lengkap untuk situs tertentu Anda.

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

  • Waktu yang diperlukan aplikasi satu halaman (SPA) untuk bertransisi dari satu "halaman" ke halaman lainnya.
  • Waktu yang diperlukan halaman untuk menampilkan data yang diambil dari database bagi pengguna yang login.
  • Waktu yang dibutuhkan aplikasi yang dirender sisi server (SSR) untuk menghidrasi.
  • Rasio cache ditemukan untuk resource yang dimuat oleh pengunjung yang kembali.
  • Latensi peristiwa klik atau peristiwa keyboard dalam game.

API untuk mengukur metrik kustom

Developer web secara historis belum memiliki banyak API level rendah untuk mengukur performa, sehingga mereka harus melakukan peretasan untuk mengukur apakah situs berperforma baik. Misalnya, Anda dapat menentukan apakah thread utama diblokir oleh tugas JavaScript yang berjalan lama dengan menjalankan loop requestAnimationFrame dan menghitung delta di antara setiap frame. Jika delta jauh lebih panjang dari kecepatan frame tampilan, Anda dapat melaporkannya sebagai tugas yang berjalan lama.

Namun, peretasan seperti ini dapat memengaruhi performa situs Anda, misalnya dengan menghabiskan baterai perangkat. Jika teknik pengukuran performa Anda menyebabkan masalah performa, data yang didapatkan dari teknik tersebut tidak akan akurat. Oleh karena itu, sebaiknya gunakan salah satu API berikut untuk membuat metrik kustom.

API Performance Observer

Dukungan Browser

  • 52
  • 79
  • 57
  • 11

Sumber

Performance Observer API adalah mekanisme yang mengumpulkan dan menampilkan data dari semua API performa lainnya yang dibahas di halaman ini. Memahami 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 biasanya tidak akan mengganggu performa halaman.

Saat membuat PerformanceObserver, teruskan callback yang berjalan setiap kali entri performa baru dikirim. Kemudian, gunakan metode observe() untuk memberi tahu observer jenis entri yang akan diproses sebagai berikut:

// Catch errors that some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Bagian berikut mencantumkan semua jenis entri yang dapat Anda amati. Di browser yang lebih baru, Anda juga dapat memeriksa jenis entri yang tersedia menggunakan properti PerformanceObserver.supportedEntryTypes statis.

Amati 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 yang berprioritas lebih tinggi.

Untuk mendapatkan entri historis, panggil observe dengan flag buffered yang ditetapkan ke true. Kemudian, browser akan menyertakan entri historis dari buffer entri performa saat callback PerformanceObserver dipanggil untuk pertama kalinya.

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

API performa lama yang harus dihindari

Sebelum Performance Observer API, developer dapat mengakses entri performa menggunakan metode berikut yang ditentukan pada objek performance. Sebaiknya jangan menggunakannya karena Anda tidak dapat memproses entri baru.

Selain itu, banyak API baru (seperti Tugas Panjang) yang tidak diekspos oleh objek performance, hanya oleh PerformanceObserver. Oleh karena itu, kecuali jika Anda sangat memerlukan kompatibilitas Internet Explorer, sebaiknya hindari metode ini dalam kode Anda dan gunakan PerformanceObserver untuk ke depannya.

API Waktu Pengguna

User Timing API adalah API pengukuran tujuan umum untuk metrik berbasis waktu. Hal ini memungkinkan Anda untuk menandai titik dalam waktu secara bebas, lalu mengukur durasi di antara tanda tersebut nanti.

// 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, User Timing API lebih baik terintegrasi dengan alat performa. Misalnya, Chrome DevTools memvisualisasikan pengukuran Waktu Pengguna di panel Performa, dan banyak penyedia analisis secara otomatis melacak setiap pengukuran yang Anda buat dan mengirim data durasi ke backend analisis mereka.

Untuk melaporkan pengukuran Waktu Pengguna, daftarkan PerformanceObserver untuk mengamati entri measure jenis:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Tugas Panjang

Dukungan Browser

  • 58
  • 79
  • x
  • x

Sumber

Long Tasks API berguna untuk menentukan kapan thread utama browser diblokir cukup lama untuk memengaruhi kecepatan frame atau latensi input. API melaporkan setiap tugas yang dijalankan lebih dari 50 milidetik (md).

Setiap kali Anda perlu menjalankan kode yang mahal, atau memuat dan mengeksekusi skrip besar, sebaiknya lacak apakah kode tersebut memblokir thread utama. Bahkan, banyak metrik tingkat yang lebih tinggi dibuat berdasarkan Long Tasks API itu sendiri (seperti Waktu untuk Interaktif (TTI) dan Total Waktu Pemblokiran (TBT)).

Untuk menentukan kapan tugas panjang terjadi, daftarkan PerformanceObserver untuk mengamati entri jenis longtask:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Waktu Elemen

Dukungan Browser

  • 77
  • 79
  • x
  • x

Sumber

Metrik Largest Contentful Paint (LCP) berguna untuk mengetahui kapan gambar atau blok teks terbesar di halaman Anda 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 elemen contentful terbesar, tetapi Anda juga dapat melaporkan elemen lain dengan secara eksplisit menambahkan atribut elementtiming ke dalamnya, dan mendaftarkan PerformanceObserver untuk mengamati jenis entri element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
...
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}
</script>

API Waktu Peristiwa

Metrik Penundaan Input Pertama (FID) mengukur waktu sejak pengguna pertama kali berinteraksi dengan halaman hingga saat browser dapat mulai memproses pengendali peristiwa sebagai respons terhadap interaksi tersebut. Namun, dalam beberapa kasus, ada baiknya juga mengukur waktu pemrosesan peristiwa itu sendiri.

Hal ini dapat dilakukan menggunakan Event Timing API, yang, selain mengukur FID, juga menampilkan sejumlah stempel waktu dalam siklus proses peristiwa, termasuk:

  • startTime: waktu saat browser menerima peristiwa.
  • processingStart: waktu saat browser dapat mulai memproses pengendali peristiwa untuk peristiwa.
  • 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 menyelesaikan semua kode sinkron yang dimulai dari pengendali peristiwa.

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

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((entryList) => {
    const firstInput = entryList.getEntries()[0];

    // Measure First Input Delay (FID).
    const firstInputDelay = firstInput.processingStart - firstInput.startTime;

    // Measure the time it takes to run all event handlers
    // Doesn't include work scheduled asynchronously using methods like
    // `requestAnimationFrame()` or `setTimeout()`.
    const firstInputProcessingTime = firstInput.processingEnd - firstInput.processingStart;

    // Measure the entire duration of the event, from when input is received by
    // the browser until the next frame can be painted after processing all
    // event handlers.
    // Doesn't include work scheduled asynchronously using
    // `requestAnimationFrame()` or `setTimeout()`.
    // For security reasons, this value is rounded to the nearest 8 ms.
    const firstInputDuration = firstInput.duration;

    // Log these values to the console.
    console.log({
      firstInputDelay,
      firstInputProcessingTime,
      firstInputDuration,
    });
  });

  po.observe({type: 'first-input', buffered: true});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

API Waktu Resource

Resource Timing API memberikan analisis mendetail kepada developer tentang cara pemuatan resource untuk halaman tertentu. Terlepas dari nama API, informasi yang disediakan tidak hanya terbatas pada data pengaturan waktu (meskipun masih banyak). Data lain yang dapat Anda akses meliputi:

  • initiatorType: cara resource diambil, seperti dari tag <script> atau <link>, atau dari fetch().
  • nextHopProtocol: protokol yang digunakan untuk mengambil resource, seperti h2 atau quic.
  • encodedBodySize dan decodedBodySize]: ukuran resource dalam bentuknya yang dienkode atau didekode (masing-masing).
  • transferSize: ukuran resource yang benar-benar ditransfer melalui jaringan. Jika resource dipenuhi menggunakan 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 untuk memahami pengaruh strategi caching resource Anda terhadap performa bagi pengunjung berulang.

Contoh berikut mencatat semua resource yang diminta oleh halaman ke dalam log dan menunjukkan apakah setiap resource terpenuhi menggunakan cache atau tidak:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });
  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Dukungan Browser

  • 57
  • 12
  • 58
  • 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 melalui stempel waktu responseStart di Navigation Timing API.

// Catch errors since  browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Developer metrik lain yang mungkin penting bagi developer layanan 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 menangkap peristiwa pengambilan.

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

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Waktu Server

Server Timing API memungkinkan Anda meneruskan data pengaturan waktu khusus permintaan dari server ke browser menggunakan header respons. Misalnya, Anda dapat menunjukkan berapa lama waktu yang dibutuhkan untuk mencari data di database untuk permintaan tertentu, yang dapat berguna dalam men-debug masalah performa yang disebabkan oleh kelambatan server.

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

Untuk menentukan data waktu server dalam respons Anda, gunakan 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.

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}