Pelajari cara menemukan interaksi yang lambat di data kolom situs agar Anda dapat menemukan peluang untuk meningkatkan Interaction to Next Paint.
Data kolom adalah data yang memberi tahu Anda pengalaman pengguna yang sebenarnya di situs Anda. Hal ini akan mengungkapkan masalah yang tidak dapat Anda temukan di data lab saja. Jika Interaction to Next Paint (INP) diperhatikan, data lapangan sangat penting dalam mengidentifikasi interaksi yang lambat, dan memberikan petunjuk penting untuk membantu Anda memperbaikinya.
Dalam panduan ini, Anda akan mempelajari cara menilai INP situs dengan cepat menggunakan data kolom dari Laporan Pengalaman Pengguna Chrome (CrUX) untuk melihat apakah situs Anda mengalami masalah terkait INP. Selanjutnya, Anda akan mempelajari cara menggunakan build atribusi library JavaScript web-vitals—dan insight baru yang diberikannya dari Long Animation Frames API (LoAF)—untuk mengumpulkan dan menafsirkan data kolom untuk interaksi yang lambat di situs Anda.
Mulai dengan CrUX untuk mengevaluasi INP situs Anda
Jika Anda tidak mengumpulkan data lapangan dari pengguna situs, CrUX mungkin merupakan titik awal yang baik. CrUX mengumpulkan data kolom dari pengguna Chrome sebenarnya yang telah memilih untuk mengirim data telemetri.
Data CrUX muncul di sejumlah area yang berbeda, dan bergantung pada cakupan informasi yang Anda cari. CrUX dapat memberikan data tentang INP dan Core Web Vitals lainnya untuk:
- Setiap halaman dan seluruh origin menggunakan PageSpeed Insights.
- Jenis halaman. Misalnya, banyak situs e-commerce memiliki jenis Halaman Detail Produk dan Halaman Listingan Produk. Anda bisa mendapatkan data CrUX untuk jenis halaman unik di Search Console.
Sebagai titik awal, Anda dapat memasukkan URL situs di PageSpeed Insights. Setelah Anda memasukkan URL, data kolom untuk URL tersebut—jika tersedia—akan ditampilkan untuk beberapa metrik, termasuk INP. Anda juga dapat menggunakan tombol untuk memeriksa nilai INP untuk dimensi seluler dan desktop.
Data ini berguna karena memberi tahu Anda jika ada masalah. Namun, CrUX tidak dapat memberi tahu Anda apa yang menyebabkan masalah. Ada banyak solusi Pemantauan Pengguna Nyata (RUM) yang tersedia untuk membantu Anda mengumpulkan data kolom dari pengguna situs untuk menjawabnya. Salah satu opsinya adalah mengumpulkan sendiri data kolom tersebut menggunakan library JavaScript web-vitals.
Mengumpulkan data kolom dengan library JavaScript web-vitals
Library JavaScript web-vitals
adalah skrip yang dapat Anda muat di situs untuk mengumpulkan data kolom dari pengguna situs Anda. Anda dapat menggunakannya untuk mencatat sejumlah metrik, termasuk INP di browser yang mendukungnya.
Build standar library web-vitals dapat digunakan untuk mendapatkan data INP dasar dari pengguna di kolom:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Untuk menganalisis data lapangan dari pengguna, Anda harus mengirimkan data ini ke suatu tempat:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Namun, data ini sendiri tidak memberi tahu Anda lebih banyak daripada CrUX. Di sinilah build atribusi library web-vitals berperan.
Melangkah lebih jauh dengan build atribusi library web-vitals
Build atribusi library web-vitals menampilkan data tambahan yang dapat Anda peroleh dari pengguna di kolom untuk membantu Anda memecahkan masalah interaksi bermasalah yang memengaruhi INP situs Anda dengan lebih baik. Data ini dapat diakses melalui objek attribution
yang muncul dalam metode onINP()
library:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});
Selain INP halaman itu sendiri, build atribusi menyediakan banyak data yang dapat Anda gunakan untuk membantu memahami alasan interaksi lambat, termasuk bagian interaksi mana yang harus Anda fokuskan. Pemodelan perilaku dapat membantu Anda menjawab pertanyaan penting seperti:
- "Apakah pengguna berinteraksi dengan halaman saat sedang dimuat?"
- "Apakah pengendali peristiwa interaksi berjalan dalam waktu lama?"
- "Apakah kode pengendali peristiwa interaksi tertunda untuk dimulai? Jika ya, apa lagi yang terjadi di thread utama pada saat itu?"
- "Apakah interaksi menyebabkan banyak pekerjaan rendering yang menunda proses rendering frame berikutnya?"
Tabel berikut menunjukkan beberapa data atribusi dasar yang dapat Anda dapatkan dari library yang dapat membantu Anda mengetahui beberapa penyebab umum interaksi lambat di situs Anda:
Kunci objek attribution
|
Data |
---|---|
interactionTarget
|
Pemilih CSS yang mengarah ke elemen yang menghasilkan nilai INP halaman—misalnya, button#save .
|
interactionType
|
Jenis interaksi, baik dari klik, ketukan, maupun input keyboard. |
inputDelay *
|
Penundaan input interaksi. |
processingDuration *
|
Waktu dari saat pemroses peristiwa pertama mulai berjalan sebagai respons terhadap interaksi pengguna hingga semua pemrosesan pemroses peristiwa selesai. |
presentationDelay *
|
Penundaan presentasi interaksi, yang terjadi sejak pengendali peristiwa selesai hingga frame berikutnya digambar. |
longAnimationFrameEntries *
|
Entri dari LoAF yang terkait dengan interaksi. Lihat bagian berikutnya untuk mengetahui info tambahan. |
Mulai dari library web-vitals versi 4, Anda bisa mendapatkan insight yang lebih mendalam tentang interaksi bermasalah melalui data yang diberikannya dengan pengelompokan fase INP (penundaan input, durasi pemrosesan, dan penundaan presentasi) dan Long Animation Frames API (LoAF).
Long Animation Frames API (LoAF)
Men-debug interaksi menggunakan data kolom adalah tugas yang menantang. Namun, dengan data dari LoAF, sekarang Anda bisa mendapatkan insight yang lebih baik tentang penyebab di balik interaksi yang lambat, karena LoAF mengekspos sejumlah pengaturan waktu yang mendetail dan data lain yang dapat Anda gunakan untuk menemukan penyebab yang tepat—dan yang lebih penting, lokasi sumber masalahnya ada di kode situs Anda.
Build atribusi library web-vitals menampilkan array entri LoAF di bagian kunci longAnimationFrameEntries
dari objek attribution
. Tabel berikut mencantumkan beberapa bit data utama yang dapat Anda temukan di setiap entri LoAF:
Kunci objek entri LoAF | Data |
---|---|
duration
|
Durasi bingkai animasi panjang, hingga saat tata letak selesai, tetapi tidak termasuk proses menggambar dan pengomposisian. |
blockingDuration
|
Jumlah total waktu dalam frame yang tidak dapat direspons dengan cepat oleh browser karena tugas yang lama. Waktu pemblokiran ini dapat mencakup tugas panjang yang menjalankan JavaScript, serta tugas rendering panjang berikutnya dalam frame. |
firstUIEventTimestamp
|
Stempel waktu saat peristiwa diantrekan selama frame. Berguna untuk mengetahui awal penundaan input interaksi. |
startTime
|
Stempel waktu awal frame. |
renderStart
|
Saat pekerjaan rendering untuk frame dimulai. Hal ini mencakup callback requestAnimationFrame (dan callback ResizeObserver jika berlaku), tetapi berpotensi sebelum pekerjaan gaya/tata letak dimulai.
|
styleAndLayoutStart
|
Saat gaya/tata letak bekerja dalam frame. Dapat berguna dalam mengetahui durasi pekerjaan gaya/tata letak saat mempertimbangkan stempel waktu lain yang tersedia. |
scripts
|
Array item yang berisi informasi atribusi skrip yang berkontribusi pada INP halaman. |
Semua informasi ini dapat memberi tahu Anda banyak hal tentang apa yang membuat interaksi menjadi lambat—tetapi array scripts
yang ditampilkan entri LoAF harus menjadi perhatian khusus:
Kunci objek atribusi skrip | Data |
---|---|
invoker
|
Pemanggil. Hal ini dapat bervariasi berdasarkan jenis invoker yang dijelaskan di baris berikutnya. Contoh pemanggil dapat berupa nilai seperti 'IMG#id.onload' , 'Window.requestAnimationFrame' , atau 'Response.json.then' . |
invokerType
|
Jenis pemanggil. Dapat berupa 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' , atau 'module-script' .
|
sourceURL
|
URL ke skrip tempat asal frame animasi panjang. |
sourceCharPosition
|
Posisi karakter dalam skrip yang diidentifikasi oleh sourceURL .
|
sourceFunctionName
|
Nama fungsi dalam skrip yang diidentifikasi. |
Setiap entri dalam array ini berisi data yang ditampilkan dalam tabel ini, yang memberi Anda informasi tentang skrip yang bertanggung jawab atas interaksi yang lambat—dan bagaimana skrip tersebut bertanggung jawab.
Mengukur dan mengidentifikasi penyebab umum di balik interaksi yang lambat
Untuk memberi Anda gambaran tentang cara menggunakan informasi ini, panduan ini sekarang akan menjelaskan cara menggunakan data LoAF yang ditampilkan di library web-vitals
untuk menentukan beberapa penyebab interaksi lambat.
Durasi pemrosesan yang lama
Durasi pemrosesan interaksi adalah waktu yang dibutuhkan callback pengendali peristiwa terdaftar milik interaksi untuk berjalan sampai selesai dan hal lain yang mungkin terjadi di antara callback tersebut. Durasi pemrosesan yang tinggi ditampilkan oleh library web-vitals:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Wajar jika Anda berpikir bahwa penyebab utama interaksi yang lambat adalah kode pengendali peristiwa Anda membutuhkan waktu terlalu lama untuk dijalankan, tetapi tidak selalu demikian. Setelah mengonfirmasi bahwa ini adalah masalahnya, Anda dapat mempelajari lebih lanjut dengan data LoAF:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Seperti yang dapat Anda lihat dalam cuplikan kode sebelumnya, Anda dapat menggunakan data LoAF untuk melacak penyebab sebenarnya di balik interaksi dengan nilai durasi pemrosesan yang tinggi, termasuk:
- Elemen dan pemroses peristiwa terdaftarnya.
- File skrip—dan posisi karakter di dalamnya—yang berisi kode pengendali peristiwa yang berjalan lama.
- Nama fungsi.
Jenis data ini sangat berharga. Anda tidak perlu lagi melakukan pekerjaan berat untuk mencari tahu interaksi mana—atau pengendali peristiwa mana—yang bertanggung jawab atas nilai durasi pemrosesan yang tinggi. Selain itu, karena skrip pihak ketiga sering kali dapat mendaftarkan pengendali peristiwanya sendiri, Anda dapat menentukan apakah kode Anda yang bertanggung jawab atau tidak. Untuk kode yang dapat Anda kontrol, sebaiknya pelajari cara mengoptimalkan tugas yang lama.
Penundaan input yang lama
Meskipun pengendali peristiwa yang berjalan lama sudah umum, ada bagian interaksi lain yang perlu dipertimbangkan. Satu bagian terjadi sebelum durasi pemrosesan, yang dikenal sebagai penundaan input. Ini adalah waktu sejak pengguna memulai interaksi, hingga saat callback pengendali peristiwanya mulai berjalan dan terjadi saat thread utama sudah memproses tugas lain. Build atribusi library web-vitals dapat memberi tahu Anda durasi penundaan input untuk interaksi:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Jika Anda melihat bahwa beberapa interaksi memiliki penundaan input yang tinggi, Anda harus mencari tahu apa yang terjadi di halaman pada saat interaksi yang menyebabkan penundaan input yang lama—dan hal ini sering kali bergantung pada apakah interaksi terjadi saat halaman dimuat, atau setelahnya.
Apakah selama pemuatan halaman?
Thread utama sering kali paling sibuk saat halaman dimuat. Selama waktu ini, semua jenis tugas sedang diantrekan dan diproses, dan jika pengguna mencoba berinteraksi dengan halaman saat semua pekerjaan ini sedang berlangsung, hal ini dapat menunda interaksi. Halaman yang memuat banyak JavaScript dapat memulai pekerjaan untuk mengompilasi dan mengevaluasi skrip, serta menjalankan fungsi yang menyiapkan halaman untuk interaksi pengguna. Pekerjaan ini dapat mengganggu jika pengguna kebetulan berinteraksi saat aktivitas ini terjadi, dan Anda dapat mengetahui apakah hal itu terjadi pada pengguna situs Anda:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Jika Anda mencatat data ini di kolom dan melihat penundaan input yang tinggi serta jenis pemanggil 'classic-script'
atau 'module-script'
, dapat dikatakan bahwa skrip di situs Anda memerlukan waktu lama untuk dievaluasi, dan memblokir thread utama cukup lama untuk menunda interaksi. Anda dapat mengurangi waktu pemblokiran ini dengan membagi skrip menjadi beberapa paket yang lebih kecil, menunda kode yang awalnya tidak digunakan untuk dimuat pada waktu yang akan datang, dan mengaudit situs Anda untuk menemukan kode yang tidak digunakan yang dapat Anda hapus sepenuhnya.
Apakah setelah pemuatan halaman?
Meskipun penundaan input sering terjadi saat halaman dimuat, penundaan input mungkin terjadi setelah halaman dimuat, karena penyebab yang sama sekali berbeda. Penyebab umum penundaan input setelah pemuatan halaman dapat berupa kode yang berjalan secara berkala karena panggilan setInterval
sebelumnya, atau bahkan callback peristiwa yang diantrekan untuk dijalankan lebih awal, dan masih diproses.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Seperti halnya pemecahan masalah nilai durasi pemrosesan yang tinggi, penundaan input yang tinggi karena penyebab yang disebutkan sebelumnya akan memberi Anda data atribusi skrip yang mendetail. Namun, yang berbeda adalah jenis pemanggil akan berubah berdasarkan sifat pekerjaan yang menunda interaksi:
'user-callback'
menunjukkan bahwa tugas pemblokiran berasal darisetInterval
,setTimeout
, atau bahkanrequestAnimationFrame
.'event-listener'
menunjukkan bahwa tugas pemblokiran berasal dari input sebelumnya yang diantrekan dan masih diproses.'resolve-promise'
dan'reject-promise'
berarti bahwa tugas pemblokiran berasal dari beberapa pekerjaan asinkron yang dimulai sebelumnya, dan diselesaikan atau ditolak pada saat pengguna mencoba berinteraksi dengan halaman, sehingga menunda interaksi.
Apa pun masalahnya, data atribusi skrip akan memberi Anda gambaran tentang tempat untuk mulai mencari, dan apakah penundaan input disebabkan oleh kode Anda sendiri, atau skrip pihak ketiga.
Penundaan presentasi yang lama
Penundaan presentasi adalah mil terakhir dari interaksi, dan dimulai saat pengendali peristiwa interaksi selesai, hingga pada titik saat frame berikutnya digambar. Hal ini terjadi saat pekerjaan di pengendali peristiwa karena interaksi mengubah status visual antarmuka pengguna. Seperti durasi pemrosesan dan penundaan input, library web-vitals dapat memberi tahu Anda berapa lama penundaan presentasi untuk suatu interaksi:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Jika Anda mencatat data ini dan melihat keterlambatan presentasi yang tinggi untuk interaksi yang berkontribusi pada INP situs Anda, penyebabnya dapat bervariasi, tetapi berikut beberapa penyebab yang perlu diwaspadai.
Gaya dan tata letak yang mahal
Penundaan presentasi yang lama dapat menimbulkan perhitungan ulang gaya dan pekerjaan tata letak yang mahal yang muncul karena sejumlah penyebab, termasuk pemilih CSS yang kompleks dan ukuran DOM yang besar. Anda dapat mengukur durasi pekerjaan ini dengan pengaturan waktu LoAF yang ditampilkan di library web-vitals:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF tidak akan memberi tahu Anda durasi pekerjaan gaya dan tata letak untuk sebuah frame, tetapi akan memberi tahu Anda kapan pekerjaan tersebut dimulai. Dengan stempel waktu awal ini, Anda dapat menggunakan data lain dari LoAF untuk menghitung durasi yang akurat dari pekerjaan tersebut dengan menentukan waktu akhir frame, dan mengurangi stempel waktu awal pekerjaan gaya dan tata letak dari waktu tersebut.
Callback requestAnimationFrame
yang berjalan lama
Salah satu potensi penyebab penundaan presentasi yang lama adalah pekerjaan berlebihan yang dilakukan dalam callback requestAnimationFrame
. Konten callback ini dieksekusi setelah pengendali peristiwa selesai berjalan, tetapi tepat sebelum penghitungan ulang gaya dan pekerjaan tata letak.
Callback ini dapat memerlukan waktu yang cukup lama untuk diselesaikan jika pekerjaan yang dilakukan di dalamnya bersifat kompleks. Jika Anda mencurigai nilai penundaan presentasi yang tinggi disebabkan oleh pekerjaan yang Anda lakukan dengan requestAnimationFrame
, Anda dapat menggunakan data LoAF yang ditampilkan oleh library web-vitals untuk mengidentifikasi skenario berikut:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Jika Anda melihat bahwa sebagian besar waktu penundaan presentasi dihabiskan dalam callback requestAnimationFrame
, pastikan pekerjaan yang Anda lakukan dalam callback ini terbatas pada pekerjaan yang menghasilkan pembaruan aktual pada antarmuka pengguna. Pekerjaan lain yang tidak menyentuh DOM atau memperbarui gaya akan menunda frame berikutnya yang digambar secara tidak perlu, jadi berhati-hatilah.
Kesimpulan
Data lapangan adalah sumber informasi terbaik yang dapat Anda gunakan untuk memahami interaksi mana yang bermasalah bagi pengguna sebenarnya di lapangan. Dengan mengandalkan alat pengumpulan data lapangan seperti library JavaScript web-vitals (atau penyedia RUM), Anda dapat lebih yakin tentang interaksi mana yang paling bermasalah, lalu melanjutkan untuk mereproduksi interaksi yang bermasalah di lab, lalu memperbaikinya.
Banner besar dari Unsplash, oleh Federico Respini.