Mengukur performance artinya mengambil angka nyata: berapa milidetik yang dibutuhkan halaman, file mana yang paling lambat, berapa kilobyte yang di-download. Tanpa angka, "kayaknya sudah cepat" cuma perasaan. Mirip timbangan badan: kalau diet tanpa pernah menimbang, kamu gak tahu usahamu berhasil atau gak.
🧪 Tebakan cepat: Lighthouse di laptopmu bilang LCP 1,2 detik, tapi data pengguna nyata bilang LCP 3,8 detik. Mana yang salah? Jawabannya ada di bagian "Lab data dan field data".
Lab data dan field data
- Lab data diukur di kondisi simulasi yang terkontrol: satu perangkat, satu jaringan tiruan, hasilnya bisa diulang. Contohnya Lighthouse, alat audit bawaan Chrome DevTools yang juga dipakai PageSpeed Insights. Bagus untuk mencari penyebab masalah sebelum deploy.
- Field data dikumpulkan dari pengguna nyata, dengan HP, jaringan, dan cara pakai mereka masing-masing. Contohnya CrUX (Chrome User Experience Report, statistik dari pengguna Chrome yang ikut berbagi data), yang ditampilkan di PageSpeed Insights. Kamu juga bisa mengumpulkannya sendiri dengan library
web-vitals. Cara ini disebut RUM, real user monitoring.
Itu jawaban tebakannya: gak ada yang salah. Laptopmu kencang, sedangkan banyak penggunamu memakai HP yang lebih lambat. Untuk menilai pengalaman pengguna, field data yang jadi patokan. Lab data dipakai untuk mencari penyebabnya. Satu lagi: INP butuh klik sungguhan, jadi Lighthouse gak bisa mengukurnya. Lighthouse menampilkan TBT (Total Blocking Time) sebagai gantinya.
Mengukur kodemu sendiri
Browser punya objek performance. Dengan mark dan measure, kamu bisa mengukur berapa lama sepotong kode berjalan:
performance.mark("sort-mulai");
angka.sort((a, b) => a - b); // kode yang mau diukur
performance.mark("sort-selesai");
performance.measure("sort", "sort-mulai", "sort-selesai");
const [hasil] = performance.getEntriesByName("sort");
console.log(hasil.duration); // misalnya 23.4 (milidetik)
performance.mark(nama)mencatat satu titik waktu dengan nama itu.performance.measure(nama, awal, akhir)mencatat jarak antara dua mark.getEntriesByName("sort")mengembalikan array, danduration-nya dalam milidetik. Mark dan measure ini juga muncul di panel Performance Chrome DevTools.
Resource Timing: tiap file yang di-download
performance.getEntriesByType("resource") memberi satu entry untuk tiap file yang di-download halaman: CSS, JavaScript, gambar, font. Tiga isinya yang paling berguna:
name: URL file-nya.duration: berapa milidetik dari request dikirim sampai byte terakhir diterima.transferSize: berapa byte yang lewat jaringan. Nilainya0kalau file diambil dari cache, atau kalau file dari domain lain gak mengizinkan angkanya dibaca (lewat headerTiming-Allow-Origin).
const data = performance.getEntriesByType("resource").map((e) => ({
name: e.name,
duration: e.duration,
transferSize: e.transferSize,
}));
Meringkas angkanya
Entry yang banyak lebih enak dibaca kalau diringkas. Pakai tiga entry ini (juga dipakai di Lab dan latihan):
function analyzeTimings(timings) {
let totalDuration = 0;
let totalBytes = 0;
let slowest = timings[0];
for (const t of timings) {
totalDuration += t.duration;
totalBytes += t.transferSize;
if (t.duration > slowest.duration) slowest = t;
}
return {
totalDuration,
slowestResource: slowest.name,
totalTransferKB: Math.floor(totalBytes / 1024),
count: timings.length,
};
}
const data = [
{ name: "style.css", duration: 120, transferSize: 15360 },
{ name: "app.js", duration: 340, transferSize: 102400 },
{ name: "logo.png", duration: 80, transferSize: 5120 },
];
console.log(analyzeTimings(data));
// { totalDuration: 540, slowestResource: "app.js", totalTransferKB: 120, count: 3 }
| Putaran | t.name |
totalDuration |
totalBytes |
slowest |
|---|---|---|---|---|
| 1 | style.css | 120 | 15.360 | style.css |
| 2 | app.js | 460 | 117.760 | app.js |
| 3 | logo.png | 540 | 122.880 | app.js |
slowestdimulai dari item pertama, lalu diganti tiap ketemudurationyang lebih besar.- 1 KB di sini 1.024 byte. 122.880 / 1.024 = 120, dan
Math.floormembulatkan ke bawah kalau hasilnya pecahan. totalDurationitu jumlah semua durasi, bukan lama halaman dimuat. File di-download bersamaan, jadi halamannya sendiri selesai lebih cepat dari 540 ms.- Urutan key di object hasilnya ikut dicek di latihan:
totalDuration,slowestResource,totalTransferKB, lalucount.
💡 Core Web Vitals dari pengguna nyata
Library web-vitals (buatan tim Chrome) mengukur LCP, INP, dan CLS di browser pengunjungmu:
import { onLCP, onINP, onCLS } from "web-vitals";
function laporkan(metric) {
console.log(metric.name, metric.value, metric.rating); // misalnya "LCP" 2180 "good"
}
onLCP(laporkan);
onINP(laporkan);
onCLS(laporkan);
metric.rating berisi "good", "needs-improvement", atau "poor". Di aplikasi sungguhan, ganti console.log dengan navigator.sendBeacon(...) untuk mengirimnya ke server analytics-mu. Di balik layar, library ini memakai PerformanceObserver, yang memberi tahu tiap ada entry baru:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log("kandidat LCP:", entry.startTime, entry.element);
}
}).observe({ type: "largest-contentful-paint", buffered: true });
⚠️ Jebakan yang sering ketemu
- Percaya satu kali tes Lighthouse di laptop kencang. Itu lab data dari satu perangkat. Cek field data untuk tahu yang dirasakan pengguna.
- Membagi dengan 1000, atau pakai
Math.round. Di latihan, KB = byte dibagi 1024, dibulatkan ke bawah denganMath.floor. - Urutan key beda. Hasil latihan dibandingkan sebagai teks JSON, jadi
{ count, totalDuration, ... }dianggap beda dengan{ totalDuration, ..., count }. - Mengira
transferSize: 0berarti file-nya kosong. Biasanya file-nya diambil dari cache.
TL;DR: Lab data (Lighthouse) diukur di simulasi terkontrol dan bagus untuk mencari penyebab. Field data (CrUX, web-vitals) datang dari pengguna nyata dan jadi patokan pengalaman mereka. Ukur kodemu dengan performance.mark dan performance.measure, dan baca tiap file lewat performance.getEntriesByType("resource") (name, duration, transferSize). Untuk meringkasnya: jumlahkan durasi, cari durasi terbesar, jumlahkan byte lalu bagi 1024 dengan Math.floor, dan hitung banyaknya entry, dengan key berurutan totalDuration, slowestResource, totalTransferKB, count.