Waktu saya pertama kali serius mendalami Core Web Vitals untuk situs pribadi, ada satu metrik yang bikin kepala pusing: INP. Awalnya saya pikir, “Ah, paling cuma masalah JavaScript yang ukurannya gede, atau gambar belum dioptimasi.” Ternyata, asumsi itu salah total. Seringkali, masalah Inp buruk itu datang dari hal-hal yang lebih tersembunyi, terutama dari kode JavaScript kita sendiri atau, lebih sering lagi, dari skrip pihak ketiga yang kita pasang.

Foto oleh Vitaly Gariev via Pexels
Saya ingat betul, sekitar akhir 2024, di salah satu proyek pribadi saya yang lumayan banyak pakai interaksi dinamis, skor INP-nya merah terus di Lighthouse. Padahal, LCP sudah hijau, CLS juga aman. Debugging-nya itu lho, butuh berminggu-minggu sampai saya sadar sumber masalahnya bukan cuma di ukuran file. Lebih ke cara JavaScript itu dieksekusi, dan bagaimana skrip-skrip ‘bantuan’ dari luar malah jadi biang kerok.
Waktu Saya Mati Kutu Karena Inp Terus Merah, Padahal Sudah Optimasi Sendiri
Dulu, saya pernah merasa sudah melakukan semua yang disarankan tutorial: kompres JavaScript, pakai defer atau async, sampai minimalkan DOM. Tapi skor Inp di PageSpeed Insights masih saja di atas 500 ms, alias merah menyala. Rasanya seperti sudah lari maraton, tapi garis finishnya mundur terus.
Pengalaman itu terjadi di situs saya sendiri, situs sederhana untuk portofolio dan blog pribadi. Anehnya, di lokal semua lancar jaya. Begitu di-deploy ke server, interaksi klik tombol atau input form jadi terasa ada delay-nya. Sedikit, tapi cukup untuk bikin pengalaman pengguna jadi kurang mulus. Saya sampai bolak-balik cek main thread activity di Chrome DevTools, cuma buat nemu tumpukan ‘Long Tasks’ yang entah dari mana asalnya.
Kenapa JavaScript yang “Kecil” Bisa Bikin Inp Buruk?
Banyak orang fokus ke ukuran file JavaScript. Kalau file-nya kecil, asumsinya pasti cepat di-load dan dieksekusi. Itu tidak sepenuhnya salah, tapi juga tidak sepenuhnya benar untuk masalah Inp buruk.
Masalah utamanya bukan cuma seberapa besar file JavaScript itu, tapi seberapa “sibuk” JavaScript itu di main thread browser. Bayangkan main thread itu seperti satu tangan yang harus melakukan banyak pekerjaan sekaligus. Kalau ada satu tugas yang butuh waktu lama (disebut long task), tangan itu tidak bisa mengerjakan tugas lain, termasuk merespons interaksi pengguna. Jadi, walaupun file-nya kecil, kalau isinya ada perhitungan kompleks yang memakan waktu atau manipulasi DOM besar-besaran, Inp bisa langsung jelek.
Misalnya, ada skrip validasi form yang terlalu agresif. Setiap kali kamu ketik satu huruf, dia langsung validasi semua input dengan regex yang rumit. Itu bisa jadi long task yang bikin main thread terblokir, dan interaksi kamu jadi terasa lambat. Padahal skripnya mungkin cuma beberapa KB.
Invasi Skrip Pihak Ketiga: Biang Kerok Tersembunyi Inp Buruk
Ini dia favorit saya. Skrip pihak ketiga. Mereka seperti tamu tak diundang yang datang dengan niat baik, tapi malah bikin rumah berantakan. Kita pasang Google Analytics, Facebook Pixel, chat widget, A/B testing tool, iklan, dan lain-lain. Masing-masing skrip ini punya kodenya sendiri, dan kita sering tidak tahu apa yang mereka lakukan di balik layar.
Saya pernah punya pengalaman pahit dengan sebuah skrip chat widget. Waktu saya pasang, tiba-tiba skor Inp situs saya drop parah. Dari yang tadinya lumayan hijau, langsung jadi kuning mendekati merah. Setelah di-profiling, ternyata skrip chat itu melakukan banyak sekali DOM manipulation dan event listener di saat yang tidak tepat, bahkan sebelum pengguna berinteraksi. Dia menginisialisasi diri dengan sangat boros, padahal tombol chat-nya belum diklik.
Masalahnya, kita tidak bisa mengoptimasi kode skrip pihak ketiga ini secara langsung. Kita cuma bisa mengontrol kapan mereka dimuat dan dieksekusi. Tapi seringkali, mereka didesain untuk langsung jalan begitu dimuat, tanpa peduli performa situs kita.
Apakah semua skrip pihak ketiga harus ditunda?
Idealnya, ya. Tapi praktiknya tidak semudah itu. Beberapa skrip pihak ketiga, seperti analytics, perlu dimuat secepat mungkin untuk menangkap data awal. Skrip iklan harus dimuat agar iklan bisa tayang dan pendapatan masuk. Ini adalah trade-off yang sering saya hadapi. Kita harus memilih: performa sempurna atau fungsionalitas penuh. Keseimbangan itu kuncinya.
Strategi yang sering saya pakai adalah menunda pemuatan skrip yang tidak kritis sampai setelah halaman selesai dimuat atau bahkan sampai pengguna berinteraksi pertama kali (misalnya, scroll atau klik). Untuk chat widget, saya tunda sampai pengguna mengarahkan kursor ke tombol chat atau setelah 10-15 detik. Ini butuh sedikit JavaScript kustom, tapi dampaknya ke Inp buruk sangat signifikan.
Strategi “Nakal” yang Saya Coba untuk Jinakkan Inp yang Membandel
Kadang, pendekatan standar saja tidak cukup. Untuk Inp yang bandel, saya sering mencoba beberapa trik yang mungkin tidak ada di daftar optimasi umum. Ini bukan solusi sempurna, ada risikonya, tapi seringkali berhasil di situasi spesifik.
Pertama, saya mulai pakai requestIdleCallback untuk tugas-tugas JavaScript yang tidak terlalu mendesak. Ini memberitahu browser untuk menjalankan kode hanya saat main thread sedang tidak sibuk. Contohnya, mengirim data analytics yang tidak real-time atau menginisialisasi komponen UI yang tidak langsung terlihat. Ini butuh sedikit refactoring kode, tapi hasilnya lumayan.
Kedua, saya belajar teknik event delegation yang lebih agresif. Daripada menambahkan event listener ke setiap elemen kecil, saya tambahkan satu event listener ke parent element yang lebih besar. Ini mengurangi jumlah listener di DOM dan mengurangi beban JavaScript saat halaman dimuat. Waktu itu, di sebuah proyek dengan banyak item interaktif, ini mengurangi waktu blokir main thread sampai 200 ms.
Ketiga, untuk skrip pihak ketiga yang paling parah, saya sempat coba memuatnya di iframe terisolasi. Ini seperti mengurung mereka di kandang sendiri, jadi kalau mereka bikin ulah, tidak akan mengganggu main thread utama. Tapi ini punya keterbatasan, terutama kalau skrip itu perlu berinteraksi langsung dengan DOM utama. Jadi, harus hati-hati dan dites betul-betul.
Yang Tidak Dibilang Dokumentasi Resmi Soal Interaksi Pengguna
Dokumentasi resmi Google atau tutorial lain sering fokus pada hal-hal teknis: kompresi, caching, defer/async. Itu penting, tapi ada nuansa lain yang sering terlewatkan saat membahas Inp buruk.
Salah satunya adalah perbedaan antara visual completeness dan interactive readiness. Halaman bisa terlihat sudah selesai dimuat (LCP hijau), tapi masih belum responsif terhadap interaksi pengguna karena JavaScript-nya masih sibuk. Ini yang seringkali bikin pengguna frustrasi: “Kok sudah muncul semua, tapi nggak bisa diklik?”
Lalu, ada juga soal input queue. Browser itu cerdas, dia akan mengantrekan event interaksi. Tapi kalau antreannya terlalu panjang karena main thread terus-terusan terblokir oleh long tasks, responsnya jadi lambat. Ini bukan cuma soal berapa lama JavaScript-nya jalan, tapi juga seberapa sering dan seberapa panjang ia memblokir main thread. Bahkan long task yang hanya 50ms, jika terjadi berkali-kali dalam rentang waktu singkat, bisa jadi masalah besar.
Saya pernah menghabiskan berjam-jam mencoba memahami kenapa sebuah halaman terasa lambat padahal tidak ada skrip yang ‘berat’. Ternyata masalahnya ada di beberapa event listener kecil yang tidak di-debounce atau throttle dengan benar. Setiap kali kursor bergerak di atas elemen tertentu, ada skrip yang jalan. Sedikit-sedikit, tapi lama-lama jadi bukit long tasks.
Memahami bagaimana browser memprioritaskan tugas dan kapan ia menganggap main thread ‘idle’ itu krusial. Ini bukan cuma sekadar menghapus kode yang tidak perlu, tapi juga mengatur jadwal eksekusi kode agar tidak bentrok dengan interaksi pengguna.
Mungkin kamu juga pernah mengalami masalah LCP lambat, yang meski berbeda dari Inp, seringkali memiliki akar masalah serupa di eksekusi JavaScript. Untuk itu, baca juga: Apa Itu Core Web Vitals Dan Mengapa Penting Untuk Seo.
Pada akhirnya, saya menyadari bahwa optimasi Inp itu bukan tentang “memperbaiki” JavaScript, tapi “mengelola” JavaScript. Kita tidak bisa menghilangkannya, tapi kita bisa mengontrol kapan, di mana, dan bagaimana ia bekerja. Ini adalah seni menyeimbangkan fungsionalitas dengan pengalaman pengguna, dan terus terang, ini adalah pertarungan yang tidak pernah usai.
