Mengoptimalkan Interaksi ke Next Paint

Pelajari cara mengoptimalkan Interaction to Next Paint situs Anda.

Interaction to Next Paint (INP) adalah metrik Core Web Vitals yang stabil dan menilai responsivitas keseluruhan halaman terhadap interaksi pengguna dengan mengamati latensi semua interaksi yang memenuhi syarat yang terjadi selama kunjungan pengguna ke suatu halaman. Nilai INP akhir adalah interaksi terpanjang yang diamati (terkadang mengabaikan pencilan).

Untuk memberikan pengalaman pengguna yang baik, situs harus mengusahakan agar Interaction to Next Paint-nya 200 milidetik atau kurang. Untuk memastikan Anda mencapai target ini bagi sebagian besar pengguna, nilai minimum yang baik untuk diukur adalah persentil ke-75 pemuatan halaman, yang disegmentasikan di seluruh perangkat seluler dan desktop.

Nilai INP yang baik adalah 200 milidetik atau kurang, nilai yang buruk lebih besar dari 500 milidetik, dan nilai di antara keduanya perlu ditingkatkan.

Bergantung pada situsnya, mungkin ada sedikit atau tidak ada interaksi—seperti halaman yang sebagian besar berisi teks dan gambar dengan sedikit atau tidak ada elemen interaktif. Atau, dalam kasus situs seperti editor teks atau game, mungkin ada ratusan—bahkan ribuan—interaksi. Dalam kedua kasus tersebut, jika INP tinggi, pengalaman pengguna akan berisiko.

Perlu waktu dan upaya untuk meningkatkan INP, tetapi hasilnya adalah pengalaman pengguna yang lebih baik. Dalam panduan ini, jalur untuk meningkatkan INP akan dibahas.

Menemukan penyebab INP yang buruk

Sebelum dapat memperbaiki interaksi yang lambat, Anda memerlukan data untuk mengetahui apakah INP situs Anda buruk atau perlu ditingkatkan. Setelah memiliki informasi tersebut, Anda dapat melanjutkan ke lab untuk mulai mendiagnosis interaksi yang lambat, dan mencari solusinya.

Menemukan interaksi lambat di lapangan

Idealnya, perjalanan Anda dalam mengoptimalkan INP akan dimulai dengan data lapangan. Jika optimal, data kolom dari penyedia Real User Monitoring (RUM) tidak hanya akan memberi Anda nilai INP halaman, tetapi juga data kontekstual yang menyoroti interaksi spesifik yang bertanggung jawab atas nilai INP itu sendiri, baik interaksi terjadi selama atau setelah pemuatan halaman, jenis interaksi (klik, penekanan tombol, atau ketukan), dan informasi berharga lainnya.

Jika Anda tidak mengandalkan penyedia RUM untuk mendapatkan data kolom, panduan data kolom INP menyarankan untuk menggunakan Laporan Pengalaman Pengguna Chrome (CrUX) melalui PageSpeed Insights untuk membantu mengisi kekurangan data. CrUX adalah set data resmi program Core Web Vitals dan memberikan ringkasan metrik tingkat tinggi untuk jutaan situs, termasuk INP. Namun, CrUX sering kali tidak memberikan data kontekstual yang akan Anda dapatkan dari penyedia RUM untuk membantu Anda menganalisis masalah. Oleh karena itu, sebaiknya situs tetap menggunakan penyedia RUM jika memungkinkan, atau menerapkan solusi RUM mereka sendiri untuk melengkapi yang tersedia di CrUX.

Mendiagnosis interaksi yang lambat di lab

Idealnya, Anda ingin mulai melakukan pengujian di lab setelah memiliki data lapangan yang menunjukkan bahwa Anda memiliki interaksi yang lambat. Jika tidak ada data lapangan, ada beberapa strategi untuk mengidentifikasi interaksi lambat di lab. Strategi tersebut mencakup mengikuti alur penggunaan umum dan menguji interaksi di sepanjang proses, serta berinteraksi dengan halaman selama pemuatan—saat thread utama sering kali paling sibuk—untuk menampilkan interaksi lambat selama bagian penting dari pengalaman pengguna tersebut.

Mengoptimalkan interaksi

Setelah mengidentifikasi interaksi yang lambat dan dapat mereproduksinya secara manual di lab, langkah berikutnya adalah mengoptimalkannya. Interaksi dapat dibagi menjadi tiga fase:

  1. Penundaan input, yang dimulai saat pengguna memulai interaksi dengan halaman, dan berakhir saat callback peristiwa untuk interaksi mulai berjalan.
  2. Durasi pemrosesan, yang terdiri dari waktu yang diperlukan untuk menjalankan callback peristiwa hingga selesai.
  3. Penundaan presentasi, yaitu waktu yang diperlukan browser untuk menampilkan frame berikutnya yang berisi hasil visual interaksi.

Jumlah ketiga fase ini adalah total latensi interaksi. Setiap fase interaksi berkontribusi pada jumlah waktu tertentu untuk total latensi interaksi, jadi penting untuk mengetahui cara mengoptimalkan setiap bagian interaksi agar berjalan dalam waktu sesedikit mungkin.

Mengidentifikasi dan mengurangi penundaan input

Saat pengguna berinteraksi dengan halaman, bagian pertama dari interaksi tersebut adalah input delay. Bergantung pada aktivitas lain di halaman, penundaan input dapat berlangsung cukup lama. Hal ini dapat disebabkan oleh aktivitas yang terjadi di thread utama (mungkin karena pemuatan, penguraian, dan kompilasi skrip), penanganan pengambilan, fungsi timer, atau bahkan dari interaksi lain yang terjadi secara berurutan dan tumpang-tindih satu sama lain.

Apa pun sumber penundaan input interaksi, Anda harus mengurangi penundaan input seminimal mungkin agar interaksi dapat mulai menjalankan callback peristiwa sesegera mungkin.

Hubungan antara evaluasi skrip dan tugas yang lama selama startup

Aspek penting dari interaktivitas dalam siklus proses halaman adalah selama startup. Saat dimuat, halaman akan dirender terlebih dahulu, tetapi perlu diingat bahwa hanya karena halaman telah dirender, bukan berarti halaman telah selesai dimuat. Bergantung pada jumlah resource yang diperlukan halaman agar berfungsi sepenuhnya, pengguna mungkin mencoba berinteraksi dengan halaman saat halaman masih dimuat.

Salah satu hal yang dapat memperpanjang penundaan input interaksi saat halaman dimuat adalah evaluasi skrip. Setelah file JavaScript diambil dari jaringan, browser masih memiliki pekerjaan yang harus dilakukan sebelum JavaScript tersebut dapat berjalan; pekerjaan tersebut mencakup mengurai skrip untuk memastikan sintaksisnya valid, mengompilasi menjadi bytecode, lalu akhirnya mengeksekusinya.

Bergantung pada ukuran skrip, pekerjaan ini dapat menyebabkan tugas yang lama di thread utama, yang akan menunda browser merespons interaksi pengguna lainnya. Agar halaman tetap responsif terhadap input pengguna selama pemuatan halaman, penting untuk memahami tindakan yang dapat Anda lakukan untuk mengurangi kemungkinan tugas yang lama selama pemuatan halaman sehingga halaman tetap cepat.

Mengoptimalkan callback peristiwa

Penundaan input hanyalah bagian pertama dari apa yang diukur INP. Anda juga harus memastikan bahwa callback peristiwa yang berjalan sebagai respons terhadap interaksi pengguna dapat diselesaikan secepat mungkin.

Sering kali menyerahkan ke thread utama

Saran umum terbaik dalam mengoptimalkan callback peristiwa adalah melakukan pekerjaan sesedikit mungkin di dalamnya. Namun, logika interaksi Anda mungkin kompleks, dan Anda mungkin hanya dapat mengurangi pekerjaan yang dilakukannya secara marginal.

Jika Anda menemukan hal ini terjadi pada situs Anda, hal berikutnya yang dapat Anda coba adalah membagi pekerjaan dalam callback peristiwa menjadi tugas terpisah. Hal ini mencegah pekerjaan kolektif menjadi tugas panjang yang memblokir thread utama, yang memungkinkan interaksi lain yang akan menunggu thread utama untuk berjalan lebih cepat.

setTimeout adalah salah satu cara untuk membagi tugas, karena callback yang diteruskan ke callback tersebut berjalan dalam tugas baru. Anda dapat menggunakan setTimeout sendiri atau memisahkan penggunaannya ke dalam fungsi terpisah untuk hasil yang lebih ergonomis.

Memberikan hasil secara tidak pandang bulu lebih baik daripada tidak memberikan hasil sama sekali. Namun, ada cara yang lebih terperinci untuk memberikan hasil ke thread utama, dan cara ini hanya melibatkan pemberian hasil segera setelah callback peristiwa yang memperbarui antarmuka pengguna sehingga logika rendering dapat berjalan lebih cepat.

Menghasilkan untuk memungkinkan pekerjaan rendering terjadi lebih cepat

Teknik pemberian yang lebih canggih melibatkan penyusunan kode dalam callback peristiwa untuk membatasi apa yang dijalankan hanya pada logika yang diperlukan untuk menerapkan pembaruan visual untuk frame berikutnya. Semua hal lainnya dapat ditangguhkan ke tugas berikutnya. Hal ini tidak hanya membuat callback tetap ringan dan gesit, tetapi juga meningkatkan waktu rendering untuk interaksi dengan tidak mengizinkan update visual untuk memblokir kode callback peristiwa.

Misalnya, bayangkan editor teks kaya yang memformat teks saat Anda mengetik, tetapi juga memperbarui aspek UI lainnya sebagai respons terhadap apa yang telah Anda tulis (seperti jumlah kata, menandai kesalahan ejaan, dan masukan visual penting lainnya). Selain itu, aplikasi mungkin juga perlu menyimpan apa yang telah Anda tulis sehingga jika Anda keluar dan kembali, Anda tidak akan kehilangan pekerjaan apa pun.

Dalam contoh ini, empat hal berikut harus terjadi sebagai respons terhadap karakter yang diketik oleh pengguna. Namun, hanya item pertama yang perlu dilakukan sebelum frame berikutnya ditampilkan.

  1. Perbarui kotak teks dengan apa yang diketik pengguna dan terapkan format yang diperlukan.
  2. Perbarui bagian UI yang menampilkan jumlah kata saat ini.
  3. Jalankan logika untuk memeriksa kesalahan ejaan.
  4. Menyimpan perubahan terbaru (secara lokal atau ke database jarak jauh).

Kode untuk melakukannya mungkin terlihat seperti berikut:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

Visualisasi berikut menunjukkan bagaimana menunda update non-penting hingga setelah frame berikutnya dapat mengurangi durasi pemrosesan dan dengan demikian latensi interaksi secara keseluruhan.

Penggambaran interaksi keyboard dan tugas berikutnya dalam dua skenario. Pada gambar atas, tugas penting render dan semua tugas latar belakang berikutnya berjalan secara sinkron hingga kesempatan untuk menampilkan frame tiba. Pada gambar bawah, pekerjaan penting render berjalan terlebih dahulu, lalu menghasilkan thread utama untuk menampilkan frame baru lebih cepat. Tugas latar belakang akan berjalan setelahnya.
Klik gambar di atas untuk melihat versi beresolusi tinggi.

Meskipun penggunaan setTimeout() di dalam panggilan requestAnimationFrame() pada contoh kode sebelumnya memang agak esoteris, ini adalah metode efektif yang berfungsi di semua browser untuk memastikan bahwa kode non-penting tidak memblokir frame berikutnya.

Menghindari thrashing tata letak

Layout thrashing—terkadang disebut layout sinkron paksa—adalah masalah performa rendering saat tata letak terjadi secara sinkron. Hal ini terjadi saat Anda memperbarui gaya di JavaScript, lalu membacanya dalam tugas yang sama—dan ada banyak properti di JavaScript yang dapat menyebabkan thrashing tata letak.

Visualisasi thrashing tata letak seperti yang ditampilkan di panel performa Chrome DevTools.
Contoh thrashing tata letak, seperti yang ditampilkan di panel performa Chrome DevTools. Tugas rendering yang melibatkan thrashing tata letak akan dicatat dengan segitiga merah di sudut kanan atas bagian stack panggilan, yang sering diberi label Hitung Ulang Gaya atau Tata Letak.

Layout-thrashing adalah bottleneck performa karena dengan memperbarui gaya, lalu segera meminta nilai gaya tersebut di JavaScript, browser dipaksa untuk melakukan pekerjaan tata letak sinkron yang seharusnya dapat menunggu untuk dilakukan secara asinkron nanti setelah callback peristiwa selesai berjalan.

Meminimalkan penundaan presentasi

Penundaan presentasi tanda interaksi berlangsung dari saat callback peristiwa interaksi selesai berjalan, hingga saat browser dapat menggambar frame berikutnya yang menampilkan perubahan visual yang dihasilkan.

Meminimalkan ukuran DOM

Jika DOM halaman kecil, pekerjaan rendering biasanya selesai dengan cepat. Namun, saat DOM menjadi sangat besar, pekerjaan rendering cenderung diskalakan dengan meningkatnya ukuran DOM. Hubungan antara tugas rendering dan ukuran DOM tidak bersifat linear, tetapi DOM besar memerlukan lebih banyak pekerjaan untuk dirender daripada DOM kecil. DOM yang besar menimbulkan masalah dalam dua kasus:

  1. Selama rendering halaman awal, DOM yang besar memerlukan banyak pekerjaan untuk merender status awal halaman.
  2. Sebagai respons terhadap interaksi pengguna, DOM yang besar dapat menyebabkan update rendering menjadi sangat mahal, sehingga meningkatkan waktu yang diperlukan browser untuk menampilkan frame berikutnya.

Perlu diingat bahwa ada kasus saat DOM besar tidak dapat dikurangi secara signifikan. Meskipun ada pendekatan yang dapat Anda lakukan untuk mengurangi ukuran DOM, seperti meratakan DOM atau menambahkan ke DOM selama interaksi pengguna agar ukuran DOM awal tetap kecil, teknik tersebut mungkin tidak akan banyak membantu.

Menggunakan content-visibility untuk merender elemen di luar layar secara lambat

Salah satu cara untuk membatasi jumlah pekerjaan rendering selama pemuatan halaman dan pekerjaan rendering sebagai respons terhadap interaksi pengguna adalah dengan mengandalkan properti content-visibility CSS, yang secara efektif berarti merender elemen secara lambat saat mendekati area tampilan. Meskipun content-visibility memerlukan beberapa latihan untuk digunakan secara efektif, sebaiknya periksa apakah hasilnya adalah waktu rendering yang lebih rendah yang dapat meningkatkan INP halaman Anda.

Perhatikan biaya performa saat merender HTML menggunakan JavaScript

Jika ada HTML, ada penguraian HTML, dan setelah browser selesai menguraikan HTML menjadi DOM, browser harus menerapkan gaya ke DOM, melakukan penghitungan tata letak, dan kemudian merender tata letak tersebut. Ini adalah biaya yang tidak dapat dihindari, tetapi cara Anda merender HTML sangatlah penting.

Saat server mengirim HTML, HTML tersebut akan diterima di browser sebagai streaming. Streaming berarti respons HTML dari server tiba dalam beberapa bagian. Browser mengoptimalkan cara menangani streaming dengan mengurai potongan streaming secara bertahap saat tiba, dan merendernya sedikit demi sedikit. Ini adalah pengoptimalan performa karena browser secara implisit menghasilkan secara berkala dan otomatis selama pemuatan halaman, dan Anda mendapatkannya secara gratis.

Meskipun kunjungan pertama ke situs mana pun akan selalu melibatkan sejumlah HTML, pendekatan umum dimulai dengan sedikit HTML awal, lalu JavaScript digunakan untuk mengisi area konten. Pembaruan berikutnya pada area konten tersebut juga terjadi sebagai hasil dari interaksi pengguna. Hal ini biasanya disebut model aplikasi web satu halaman (SPA). Salah satu kelemahan pola ini adalah, dengan merender HTML dengan JavaScript di klien, Anda tidak hanya mendapatkan biaya pemrosesan JavaScript untuk membuat HTML tersebut, tetapi juga browser tidak akan menghasilkan hingga selesai mengurai HTML tersebut, dan merendernya.

Namun, penting untuk diingat bahwa bahkan situs yang bukan SPA mungkin akan melibatkan sejumlah rendering HTML melalui JavaScript sebagai hasil interaksi. Hal ini umumnya tidak masalah, selama Anda tidak merender HTML dalam jumlah besar di klien, yang dapat menunda presentasi frame berikutnya. Namun, penting untuk memahami implikasi performa dari pendekatan ini untuk merender HTML di browser, dan bagaimana hal ini dapat memengaruhi responsivitas situs Anda terhadap input pengguna jika Anda merender banyak HTML melalui JavaScript.

Kesimpulan

Meningkatkan INP situs Anda adalah proses yang berulang. Saat Anda memperbaiki interaksi lambat di lapangan, kemungkinan besar—terutama jika situs Anda menyediakan banyak interaktivitas—Anda akan mulai menemukan interaksi lambat lainnya, dan Anda juga harus mengoptimalkannya.

Kunci untuk meningkatkan INP adalah persistensi. Seiring waktu, Anda dapat membuat halaman Anda menjadi responsif sehingga pengguna puas dengan pengalaman yang Anda berikan kepada mereka. Kemungkinan besar, saat mengembangkan fitur baru untuk pengguna, Anda mungkin perlu melalui proses yang sama dalam mengoptimalkan interaksi khusus untuk mereka. Hal ini akan memerlukan waktu dan tenaga, tetapi waktu dan tenaga tersebut akan terbayar.

Gambar hero dari Unsplash, oleh David Pisnoy dan diubah sesuai dengan lisensi Unsplash.