Optimasi INP: Core Web Vital yang Menggantikan FID

Foto oleh Nicola since 1972 on flickr
Interaction to Next Paint mengukur latensi setiap klik, tap, dan interaksi keyboard selama kunjungan halaman lalu melaporkan yang paling lambat pada persentil ke tujuh puluh lima. First Input Delay hanya mengukur delay sebelum interaksi pertama ditangani, sehingga tidak menangkap kelambatan yang terjadi belakangan dalam sesi setelah state dan ukuran DOM bertambah besar.
Google menilai INP 200 milidetik atau kurang sebagai baik, 200 hingga 500 milidetik sebagai perlu perbaikan, dan di atas 500 milidetik sebagai buruk. Ambang ini berlaku pada persentil ke tujuh puluh lima dari kunjungan nyata, dipisah antara mobile dan desktop.
Main thread hanya bisa menjalankan satu task pada satu waktu, sehingga skrip yang berjalan lebih dari lima puluh milidetik tanpa berhenti akan menghambat penanganan input dan proses menggambar. Jika long task tersebut kebetulan berjalan saat atau tepat setelah interaksi pengguna, browser tidak bisa merespons sampai task itu selesai, yang langsung memperbesar INP.
Metode scheduler.yield menghentikan eksekusi sementara dan menempatkan lanjutannya di depan antrean task, sehingga langsung melanjutkan begitu penanganan input berprioritas lebih tinggi selesai. Metode ini rilis stabil di Chrome 129 dan kini didukung semua browser utama kecuali Safari, jadi lakukan feature detection dan gunakan yield berbasis setTimeout sebagai cadangan bila tidak tersedia.
Bisa. Pustaka open source web-vitals dari Google mendengarkan Event Timing API dan melaporkan INP langsung dari sesi nyata, lengkap dengan data atribusi yang mengidentifikasi elemen DOM dan jenis event penyebab interaksi paling lambat. Alat lab seperti Lighthouse hanya menyimulasikan beberapa interaksi terskrip dan tidak dapat menggantikan data lapangan.

Foto oleh Nicola since 1972 on flickr
Ringkasan Utama
Interaction to Next Paint (INP) adalah Core Web Vital yang menggantikan First Input Delay sejak 2024, menilai interaksi paling lambat pada sebuah halaman, bukan hanya klik pertamanya. Memperbaiki skor INP yang buruk berarti memecah long task JavaScript, melakukan yielding ke main thread, dan mengukur pengguna nyata dengan pustaka web-vitals, bukan hanya mengandalkan hasil uji di lab.
First Input Delay dulu hanya mengukur satu hal, yaitu berapa lama browser menunggu sebelum bisa mulai menangani klik, tap, atau tekanan tombol pertama pada sebuah halaman. Metrik ini resmi dipensiunkan pada Maret 2024 dan digantikan oleh Interaction to Next Paint, sebuah Core Web Vital yang mengamati setiap interaksi selama seluruh kunjungan dan melaporkan interaksi paling lambat yang masih terhitung setelah outlier disingkirkan. Jika tim Anda bertahun-tahun mengejar skor FID yang baik namun tetap melihat INP berwarna merah di Search Console, inilah alasannya, FID tidak pernah memedulikan apa yang terjadi setelah tap pertama, sementara sebagian besar kelambatan sesungguhnya terjadi belakangan, jauh di dalam sesi, setelah state, listener, dan node DOM menumpuk.
Artikel ini membahas apa yang sesungguhnya diukur oleh INP, mengapa long task JavaScript hampir selalu menjadi akar penyebab skor yang buruk, dan teknik konkret untuk mengembalikan INP ke bawah ambang baik dua ratus milidetik, mulai dari memecah long task, yielding ke main thread dengan API penjadwalan modern, memangkas pekerjaan yang tidak perlu di dalam event handler, hingga menginstrumentasi pengguna nyata dengan pustaka web-vitals sehingga optimasi Anda didasarkan pada data lapangan sesungguhnya, bukan sekadar satu trace lab.
INP mengamati setiap klik, tap, dan interaksi keyboard yang terjadi selama kunjungan halaman lalu menghitung nilai latensi untuk masing-masing, yang terdiri dari tiga fase, yaitu input delay sebelum event handler mulai berjalan, processing time saat handler dieksekusi, dan presentation delay hingga browser menggambar frame berikutnya. INP kemudian melaporkan interaksi mana yang paling lambat setelah sejumlah kecil outlier statistik dibuang pada halaman dengan banyak interaksi, dievaluasi pada persentil ke tujuh puluh lima dari kunjungan nyata, dipisah antara mobile dan desktop. Sebuah halaman dengan satu dropdown lambat yang tersembunyi di bagian bawah tetap bisa gagal INP meski setiap klik lain terasa instan, karena metrik ini memang dirancang untuk menangkap pengalaman terburuk yang dialami pengunjung biasa, bukan pengalaman rata-rata.
| Peringkat | Ambang Persentil ke 75 |
|---|---|
| Baik | 200 milidetik atau kurang |
| Perlu Perbaikan | Antara 200 dan 500 milidetik |
| Buruk | Lebih dari 500 milidetik |
Main thread browser hanya bisa mengerjakan satu hal pada satu waktu. Layout, kalkulasi ulang style, eksekusi JavaScript, dan proses menggambar semuanya berebut thread yang sama, sehingga skrip apa pun yang berjalan tanpa henti lebih dari lima puluh milidetik akan dikategorikan sebagai long task dan menghambat semua hal lain, termasuk handler klik yang sedang ditunggu pengguna. Long task biasanya muncul dari beberapa penyebab umum pada aplikasi Next.js dan React pada umumnya.
Buka Chrome DevTools, rekam Performance trace sambil mengklik interaksi yang paling lambat, lalu perhatikan bilah long task bertanda merah pada jalur Main. Panel Performance Insights yang lebih baru akan langsung memberi label pada setiap fase, sehingga Anda jarang perlu menebak bagian mana dari interaksi yang menjadi penyebab utamanya.
Perbaikan untuk long task jarang berupa membuat pekerjaannya sendiri lebih cepat, melainkan memecah pekerjaan tersebut menjadi bagian-bagian kecil dan mengembalikan kendali ke browser di antara bagian-bagian itu agar browser bisa menggambar, menjalankan input handler, dan tetap responsif. Pola ini disebut yielding. Dahulu developer mensimulasikannya dengan setTimeout, yang menunda callback ke akhir antrean task, namun pendekatan itu membuat pekerjaan berprioritas rendah bisa menyerobot antrean sebelum pekerjaan yang ditunggu pengguna. Metode scheduler.yield, yang rilis stabil di Chrome 129 pada September 2024 dan kini didukung di browser berbasis Chromium serta Firefox, mengatasi hal ini dengan menghentikan eksekusi sementara dan menempatkan lanjutannya di depan antrean, sehingga kode Anda melanjutkan segera setelah penanganan input berprioritas lebih tinggi selesai, bukan menunggu di belakang setiap timer lain yang mengantre.
// Feature-detect scheduler.yield(), fall back to a microtask-friendly helper
function yieldToMain() {
if ('scheduler' in window && 'yield' in window.scheduler) {
return window.scheduler.yield()
}
// Fallback: postMessage-based macrotask yield (setTimeout(0) is throttled)
return new Promise((resolve) => setTimeout(resolve, 0))
}
async function processLargeList(items, renderRow) {
for (let i = 0; i < items.length; i++) {
renderRow(items[i])
// Yield every N items instead of every item, or every frame budget (~5ms)
if (i % 20 === 0) {
await yieldToMain()
}
}
}
// In an interaction handler: paint feedback first, then do heavy work
button.addEventListener('click', async () => {
showSpinner() // cheap, paints immediately
await yieldToMain() // let the browser paint the spinner
await processLargeList(rows, renderRow)
hideSpinner()
})Saat Anda merefaktor interaksi yang memicu long task, ikuti langkah-langkah berikut secara berurutan daripada langsung memakai scheduler.yield di mana-mana, karena yielding yang terlalu sering juga membawa overhead tersendiri.
Jangan membaca properti DOM yang memicu layout seperti offsetHeight atau getBoundingClientRect segera setelah menulis perubahan style di dalam task yang sama. Kombinasi itu memaksa kalkulasi ulang layout secara sinkron, yang dikenal sebagai layout thrashing, dan diam-diam menambah processing time tanpa muncul sebagai satu long task yang jelas, hanya berupa kelambatan kumulatif di banyak interaksi.
Alat lab seperti Lighthouse menyimulasikan beberapa interaksi terskrip pada satu mesin, yang berguna untuk menangkap regresi di CI namun tidak memberi tahu apa pun tentang bagaimana pengunjung sesungguhnya, dengan perangkat dan jaringan mereka sendiri, merasakan responsivitas. Pustaka open source web-vitals dari Google mendengarkan Event Timing API yang sama dengan yang dipakai Chrome secara internal dan melaporkan INP langsung dari sesi nyata, lengkap dengan data atribusi yang menyebutkan target DOM dan jenis event yang menjadi penyebab interaksi paling lambat, sehingga Anda bisa langsung berpindah dari peringatan dashboard ke komponen tepat yang menyebabkannya.
import { onINP } from 'web-vitals'
onINP((metric) => {
// metric.value is in milliseconds, metric.rating is
// 'good' | 'needs-improvement' | 'poor'
const target = metric.attribution?.interactionTarget
const eventType = metric.attribution?.interactionType
navigator.sendBeacon('/analytics/web-vitals', JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating,
target,
eventType,
id: metric.id,
}))
}, { reportAllChanges: false })Anda tidak memerlukan pipeline analitik khusus untuk mulai memantau INP di produksi. Integrasi kecil yang ditambahkan di atas sistem pelacakan page view yang sudah ada sudah cukup untuk mulai menemukan regresi nyata dalam hitungan hari.
Tim yang memadukan scheduler.yield untuk pekerjaan di main thread dengan Web Worker untuk komputasi yang benar-benar berat biasanya mendapatkan peningkatan INP terbesar dengan perubahan kode paling sedikit, karena kedua teknik ini tidak memerlukan perombakan cara state mengalir di dalam aplikasi.