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 bagaimana pengguna yang sebenarnya menggunakan web secara keseluruhan.
- Bandingkan situs Anda dengan situs pesaing.
- Lacak data yang berguna dan bisa 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 mendapatkan pengalaman lengkap untuk situs Anda.
Metrik kustom memungkinkan Anda mengukur aspek pengalaman situs 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 untuk pengguna yang login.
- Waktu yang diperlukan 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
Secara historis, developer web tidak memiliki banyak API tingkat rendah untuk mengukur performa, dan akibatnya mereka harus menggunakan hack untuk mengukur apakah situs berperforma baik.
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 jauh lebih lama daripada kecepatan frame layar, Anda dapat melaporkannya sebagai tugas yang lama. Namun, hack semacam itu tidak direkomendasikan karena sebenarnya hack tersebut memengaruhi performa (misalnya, dengan menghabiskan baterai).
Aturan pertama pengukuran performa yang efektif adalah memastikan teknik pengukuran performa Anda tidak menyebabkan masalah performa itu sendiri. Jadi, untuk metrik kustom apa pun yang Anda ukur di situs, sebaiknya gunakan salah satu API berikut jika memungkinkan.
Performance Observer API
Performance Observer API adalah mekanisme yang mengumpulkan dan menampilkan data dari semua API performa lainnya yang dibahas di halaman ini. Memahaminya 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 yang akan dijalankan setiap kali entri performa baru dikirim. Kemudian, Anda memberi tahu observer jenis entri yang akan 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 lambat kode analisis performa agar tidak memblokir resource dengan prioritas lebih tinggi.
Untuk mendapatkan entri historis (setelah terjadi), tetapkan tanda buffered
ke true
saat Anda memanggil observe()
. Browser akan menyertakan entri historis dari buffer entri performa saat pertama kali callback PerformanceObserver
Anda 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 diekspos melalui objek performance
, tetapi hanya diekspos melalui PerformanceObserver
.
Kecuali jika Anda secara khusus memerlukan kompatibilitas dengan Internet Explorer, sebaiknya hindari metode ini dalam kode Anda dan gunakan PerformanceObserver
ke depannya.
API Waktu Pengguna
User Timing API adalah API pengukuran tujuan umum untuk metrik berbasis waktu. Dengan ini, Anda dapat menandai titik waktu secara arbitrer, 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 serupa, manfaat menggunakan User Timing API adalah API ini 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 buat dan mengirim data durasi ke backend analisis mereka.
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});
Long Tasks API
Long Tasks API berguna untuk mengetahui kapan thread utama browser diblokir cukup lama untuk memengaruhi kecepatan frame atau latensi input. API akan melaporkan setiap tugas yang dieksekusi selama lebih dari 50 milidetik.
Setiap kali Anda perlu menjalankan kode yang mahal, atau memuat dan mengeksekusi skrip besar, sebaiknya lacak apakah kode tersebut memblokir thread utama. Faktanya, banyak metrik tingkat tinggi yang dibuat berdasarkan 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
Long Animation Frames API adalah iterasi baru dari Long Tasks API yang melihat frame panjang—bukan tugas panjang—yang berdurasi lebih dari 50 milidetik. Hal ini mengatasi beberapa kelemahan Long Tasks API, termasuk atribusi yang lebih baik dan cakupan penundaan yang berpotensi bermasalah yang lebih luas.
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});
Element Timing API
Metrik Largest Contentful Paint (LCP) berguna untuk mengetahui kapan gambar atau blok teks terbesar di-paint 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>
Event Timing API
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 sering kali 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 karena alasan keamanan) antara saat browser menerima peristiwa hingga dapat menggambar frame berikutnya setelah selesai menjalankan 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});
Resource Timing API
Resource Timing API memberi developer insight mendetail 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 mencakup:
initiatorType
: cara resource diambil: seperti dari tag<script>
atau<link>
, atau dari panggilanfetch()
.nextHopProtocol
: protokol yang digunakan untuk mengambil resource, sepertih2
atauquic
.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 dapat jauh lebih kecil daripadaencodedBodySize
, dan dalam beberapa kasus dapat nol (jika tidak diperlukan validasi ulang cache).
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});
Navigation Timing API
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 mungkin penting bagi 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
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 mengaitkan data performa server dengan metrik bisnis lainnya yang mungkin diukur oleh alat analisis ini.
Untuk menentukan data pengaturan 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 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});