Core Web Vitals: INP — Performance

Interaction to Next Paint (INP) INP adalah metrik Core Web Vitals yang mengukur responsivitas halaman terhadap interaksi pengguna. Berbeda dari FID (First…

INP (Interaction to Next Paint) adalah metrik Core Web Vitals untuk responsivitas: waktu dari user klik, tap, atau menekan tombol keyboard, sampai layar menampilkan hasilnya di frame berikutnya. Batasnya sudah kamu kenal dari pelajaran Core Web Vitals. Di sini kita bongkar isinya. Bayangin pesan kopi di kafe yang ramai: kamu menunggu kasir selesai melayani orang sebelumnya, barista membuat kopimu, lalu kopinya diantar ke meja. Waktu yang kamu rasakan adalah ketiganya dijumlah, bukan cuma lamanya barista bekerja.

🧪 Tebakan cepat: waktu user klik "Tambah ke keranjang", ada script analytics 180 ms yang baru mulai jalan. Event handler-nya butuh 250 ms, dan menggambar hasilnya 100 ms. Berapa INP interaksi ini: 250, 430, atau 530 ms? Jawabannya ada di bagian "Tiga bagian sebuah interaksi".

Tiga bagian sebuah interaksi

Semua JavaScript halaman, juga style, layout, dan paint, dikerjakan di satu jalur yang sama: main thread. Dia cuma bisa mengerjakan satu hal dalam satu waktu. Satu interaksi melewati tiga bagian:

Bagian Penyebab di contoh Lama
Input delay script analytics yang lagi jalan 180 ms
Processing time handler "Tambah ke keranjang" 250 ms
Presentation delay 1.500 baris digambar ulang 100 ms
INP interaksi ini 530 ms

Itu jawaban tebakannya: 530 ms, dan itu poor. Batasnya: good maksimal 200 ms, needs-improvement sampai 500 ms, poor di atas 500 ms. Angka yang tepat 200 masih good. INP halaman diambil dari interaksi yang paling lambat selama kunjungan (kalau interaksinya banyak sekali, beberapa yang paling ekstrem diabaikan), lalu Google menilainya di persentil ke-75 kunjungan nyata.

INP menggantikan FID (First Input Delay) sejak Maret 2024. FID cuma mengukur input delay, dan cuma untuk interaksi pertama. Di contoh tadi FID-nya 180 ms dan terlihat good, padahal user menunggu 530 ms.

Long task: kenapa main thread macet

Long task adalah task yang jalan lebih dari 50 ms di main thread. Selama long task jalan, browser gak bisa menjalankan handler klik dan gak bisa menggambar. Script analytics 180 ms dan handler 250 ms tadi dua-duanya long task.

function classifyInp(milliseconds) {
  if (milliseconds <= 200) return "good";
  if (milliseconds <= 500) return "needs-improvement";
  return "poor";
}

function identifyBlockingTasks(tasks) {
  return tasks.filter((task) => task.duration > 50); // long task: lebih dari 50 ms
}

console.log(classifyInp(530)); // "poor"

const tasks = [
  { name: "parseHTML", duration: 30 },
  { name: "evalScript", duration: 120 },
  { name: "styleRecalc", duration: 20 },
  { name: "fetchData", duration: 80 },
];
console.log(identifyBlockingTasks(tasks));
// [{ name: "evalScript", duration: 120 }, { name: "fetchData", duration: 80 }]

Yield: kasih main thread kesempatan

Cara utama mengecilkan INP adalah yield (mengalah): pecah kerja panjang jadi potongan pendek, dan di antara potongan, kembalikan main thread ke browser supaya dia sempat menggambar dan menerima klik.

function yieldToMain() {
  if (globalThis.scheduler?.yield) return scheduler.yield();
  return new Promise((resolve) => setTimeout(resolve, 0)); // cadangan
}

button.addEventListener("click", async () => {
  updateCartBadge();       // yang dilihat user dikerjakan duluan
  for (const chunk of chunks) {
    await yieldToMain();   // browser boleh menggambar dan menerima klik dulu
    processChunk(chunk);   // tiap potongan di bawah 50 ms
  }
});

Di contoh tadi, kalau script analytics juga dipecah per 50 ms dan handler-nya yield setelah 12 ms, INP-nya jadi 50 + 12 + 100 = 162 ms: good.

Bagian yang besar Cara mengecilkannya
Input delay pecah long task lain dengan yield, tunda script pihak ketiga
Processing time kerjakan yang dilihat user dulu lalu yield, debounce handler berat, pindahkan hitungan berat ke Web Worker
Presentation delay ubah DOM sesedikit mungkin: batch, virtual scrolling, hindari layout thrashing

⚠️ Jebakan yang sering ketemu

TL;DR: INP adalah waktu dari interaksi sampai frame berikutnya digambar, yaitu input delay + processing time + presentation delay. Good maksimal 200 ms, needs-improvement sampai 500 ms, poor di atas 500 ms, dan INP halaman diambil dari interaksi yang paling lambat. INP menggantikan FID sejak Maret 2024, yang cuma mengukur input delay interaksi pertama. Long task adalah task lebih dari 50 ms di main thread. Kecilkan INP dengan yield: kerjakan yang dilihat user dulu, lalu await scheduler.yield() (cadangan setTimeout) di antara potongan pendek.

Yang akan kamu pelajari