Mengoptimalkan Interaksi ke Next Paint

Pelajari cara mengoptimalkan Interaksi situs Anda dengan Next Paint.

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

Untuk memberikan pengalaman pengguna yang baik, situs harus berusaha memiliki Interaction to Next Paint 200 milidetik atau kurang. Guna memastikan Anda mencapai target ini untuk sebagian besar pengguna Anda, batas yang perlu diukur adalah persentil ke-75 dari 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 apa pun di antaranya perlu ditingkatkan.

Bergantung pada situs, mungkin hanya ada sedikit atau tidak ada interaksi sama sekali—seperti halaman yang sebagian besar berisi teks dan gambar dengan sedikit atau tanpa elemen interaktif. Atau, untuk situs seperti editor teks atau game, mungkin ada ratusan—bahkan ribuan—interaksi. Dalam kedua kasus tersebut, jika ada INP yang 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 dipelajari.

Mencari tahu penyebab INP yang buruk

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

Menemukan interaksi lambat di lapangan

Idealnya, perjalanan Anda dalam mengoptimalkan INP akan dimulai dengan data kolom. Data kolom dari penyedia Pemantauan Pengguna Nyata (RUM) tidak hanya akan memberi Anda nilai INP halaman, tetapi juga data kontekstual yang menyoroti interaksi spesifik yang menyebabkan nilai INP itu sendiri, apakah interaksi terjadi selama atau setelah pemuatan halaman, jenis interaksi (klik, penekanan tombol, atau ketuk), dan informasi berharga lainnya.

Jika Anda tidak mengandalkan penyedia RUM untuk mendapatkan data kolom, panduan data kolom INP menyarankan penggunaan 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 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 apa yang tersedia di CrUX.

Mendiagnosis interaksi lambat di lab

Idealnya, Anda perlu memulai pengujian di lab setelah memiliki data kolom yang menunjukkan interaksi Anda lambat. Dengan tidak adanya data lapangan, ada beberapa strategi untuk mengidentifikasi interaksi yang lambat di lab. Strategi tersebut mencakup mengikuti alur pengguna umum dan menguji interaksi selama proses berlangsung, serta berinteraksi dengan halaman selama pemuatan—saat thread utama sering kali tersibuk—untuk menampilkan interaksi lambat selama bagian penting pengalaman pengguna tersebut.

Optimalkan interaksi

Setelah Anda 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 callback peristiwa untuk berjalan hingga selesai.
  3. Penundaan presentasi, yaitu waktu yang diperlukan browser untuk menampilkan frame berikutnya yang berisi hasil visual interaksi.

Jumlah dari ketiga fase ini adalah total latensi interaksi. Setiap fase interaksi berkontribusi pada sejumlah waktu terhadap total latensi interaksi, jadi penting untuk mengetahui cara mengoptimalkan setiap bagian interaksi agar berjalan sesingkat mungkin.

Mengidentifikasi dan mengurangi penundaan input

Saat pengguna berinteraksi dengan halaman, bagian pertama dari interaksi tersebut adalah penundaan input. Bergantung pada aktivitas lain di halaman, penundaan input bisa 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 sehingga interaksi dapat mulai menjalankan callback peristiwa sesegera mungkin.

Hubungan antara evaluasi skrip dan tugas panjang selama startup

Aspek penting interaktivitas dalam siklus proses halaman adalah selama startup. Saat dimuat, halaman pada awalnya akan dirender. Namun, penting untuk diingat bahwa hanya karena halaman telah dirender, bukan berarti halaman tersebut selesai dimuat. Bergantung pada jumlah resource yang diperlukan halaman agar berfungsi secara penuh, pengguna mungkin dapat mencoba berinteraksi dengan halaman saat masih dimuat.

Satu hal yang dapat memperpanjang penundaan input interaksi saat halaman dimuat adalah evaluasi skrip. Setelah file JavaScript diambil dari jaringan, browser masih harus dilakukan sebelum JavaScript dapat berjalan; pekerjaan tersebut termasuk mengurai skrip untuk memastikan sintaksnya valid, mengompilasinya menjadi bytecode, kemudian mengeksekusinya.

Tergantung pada ukuran skrip, pekerjaan ini bisa menimbulkan tugas yang panjang pada thread utama, yang akan menunda browser merespons interaksi pengguna lain. Agar halaman Anda tetap responsif terhadap input pengguna selama pemuatan halaman, penting untuk memahami apa yang dapat Anda lakukan untuk mengurangi kemungkinan tugas yang lama selama pemuatan halaman sehingga halaman tetap ringkas.

Mengoptimalkan callback peristiwa

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

Sering menampilkan hasil ke thread utama

Saran umum terbaik dalam mengoptimalkan callback peristiwa adalah melakukan sedikit pekerjaan di dalamnya. Namun, logika interaksi Anda mungkin rumit, dan Anda mungkin hanya dapat sedikit mengurangi pekerjaan yang mereka lakukan.

Jika Anda mendapati hal ini berlaku untuk situs Anda, hal berikutnya yang dapat Anda coba adalah memecah pekerjaan tersebut di callback peristiwa menjadi tugas-tugas terpisah. Hal ini mencegah pekerjaan kolektif menjadi tugas panjang yang memblokir thread utama, sehingga memungkinkan interaksi lain yang seharusnya menunggu thread utama berjalan lebih cepat.

setTimeout adalah salah satu cara untuk memecah tugas, karena callback yang diteruskan ke metode tersebut berjalan di tugas baru. Anda dapat menggunakan setTimeout saja atau memisahkan penggunaannya ke dalam fungsi terpisah agar menghasilkan hasil yang lebih ergonomis.

Menghasilkan tanpa diskriminasi lebih baik daripada tidak menghasilkan sama sekali—namun, ada cara yang lebih bernuansa untuk menghasilkan thread utama, dan itu hanya melibatkan hasil segera setelah callback peristiwa yang memperbarui antarmuka pengguna sehingga logika rendering dapat berjalan lebih cepat.

Hasil yang memungkinkan proses rendering terjadi lebih cepat

Teknik menghasilkan yang lebih canggih melibatkan penataan kode dalam callback peristiwa untuk membatasi apa yang dijalankan hanya pada logika yang diperlukan guna menerapkan update visual untuk frame berikutnya. Hal lainnya bisa ditunda, untuk tugas selanjutnya. Hal ini tidak hanya membuat callback tetap ringan dan gesit, tetapi juga meningkatkan waktu rendering untuk interaksi dengan tidak mengizinkan update visual memblokir kode callback peristiwa.

Misalnya, bayangkan ada editor rich text yang memformat teks saat Anda mengetik, tetapi juga memperbarui aspek UI lainnya sebagai respons atas apa yang Anda tulis (seperti jumlah kata, menyoroti 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 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 sesuai dengan yang diketik pengguna dan terapkan format yang diperlukan.
  2. Mengupdate bagian UI yang menampilkan jumlah kata saat ini.
  3. Jalankan logika untuk memeriksa kesalahan ejaan.
  4. Simpan perubahan terbaru (baik 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-kritis hingga setelah {i>frame<i} berikutnya dapat mengurangi durasi pemrosesan dan dengan demikian juga latensi interaksi secara keseluruhan.

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

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

Menghindari layout thrashing

Layout thrashing—terkadang disebut tata letak sinkron paksa—adalah masalah performa rendering di mana 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 layout thrashing seperti yang ditampilkan di panel performa Chrome DevTools.
Contoh layout thrashing, seperti yang ditampilkan di panel performa Chrome DevTools. Tugas rendering yang melibatkan layout thrashing akan ditandai dengan segitiga merah di sudut kanan atas bagian stack panggilan, yang sering kali diberi label Recalculated Style atau Layout.

Layout thrashing merupakan bottleneck performa karena dengan mengupdate gaya lalu segera meminta nilai gaya tersebut di JavaScript, browser akan dipaksa untuk melakukan tugas tata letak sinkron. Jika tidak, browser tersebut bisa menunggu untuk berjalan secara asinkron nanti setelah callback peristiwa selesai berjalan.

Minimalkan penundaan presentasi

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

Meminimalkan ukuran DOM

Jika DOM halaman berukuran kecil, proses rendering biasanya selesai dengan cepat. Namun, jika DOM menjadi sangat besar, pekerjaan rendering cenderung diskalakan dengan bertambahnya ukuran DOM. Hubungan antara tugas rendering dan ukuran DOM bukan yang linear, namun DOM besar membutuhkan lebih banyak upaya untuk dirender daripada DOM kecil. DOM besar akan bermasalah dalam dua kasus:

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

Ingatlah bahwa ada kalanya 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 Anda tetap kecil, teknik tersebut mungkin hanya berdampak jauh.

Menggunakan content-visibility untuk merender elemen di luar layar dengan 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 dengan lambat saat mendekati area tampilan. Meskipun content-visibility dapat memerlukan beberapa latihan untuk digunakan secara efektif, sebaiknya selidiki apakah hasilnya adalah waktu rendering yang lebih rendah yang dapat meningkatkan INP halaman Anda.

Perhatikan biaya performa saat merender HTML menggunakan JavaScript

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

Saat server mengirim HTML, HTML akan masuk ke browser sebagai streaming. Streaming berarti bahwa respons HTML dari server tiba dalam potongan. Browser mengoptimalkan caranya menangani streaming dengan menguraikan potongan streaming tersebut secara bertahap saat streaming tersebut tiba, dan merendernya sedikit demi sedikit. Ini adalah pengoptimalan kinerja di mana browser secara implisit menghasilkan hasil secara berkala dan otomatis selama pemuatan halaman, dan Anda mendapatkannya gratis.

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

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

Kesimpulan

Meningkatkan INP situs Anda adalah proses berulang. Saat Anda memperbaiki interaksi yang lambat di lapangan, peluangnya bagus, 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. Pada waktunya, Anda bisa menyesuaikan respons halaman sehingga pengguna puas dengan pengalaman yang Anda berikan. Kemungkinannya juga bagus bahwa saat Anda mengembangkan fitur baru untuk pengguna, Anda mungkin perlu melalui proses yang sama dalam mengoptimalkan interaksi khusus untuk mereka. Hal ini membutuhkan waktu dan usaha, tetapi semua waktu dan upaya akan dicurahkan dengan baik.

Banner besar dari Unsplash, oleh David Pisnoy dan dimodifikasi sesuai dengan lisensi Unsplash.