Cara Kerja Bagian Dalam Proses Perender
Artikel ini adalah bagian 3 dari 4 bagian seri blog yang membahas cara kerja browser. Sebelumnya, kita telah membahas arsitektur multiproses dan alur navigasi. Dalam postingan ini, kita akan melihat apa yang terjadi di dalam proses perender.
Proses perender menyentuh banyak aspek performa web. Karena ada banyak hal yang terjadi di dalam proses perender, postingan ini hanyalah ringkasan umum. Jika Anda ingin mempelajari lebih lanjut, bagian Performa pada Dasar-Dasar Web memiliki banyak referensi lainnya.
Proses perender menangani konten web
Proses perender bertanggung jawab atas semua yang terjadi di dalam tab. Dalam proses perender, thread utama menangani sebagian besar kode yang Anda kirim ke pengguna. Terkadang bagian dari JavaScript Anda ditangani oleh thread pekerja jika Anda menggunakan pekerja web atau pekerja layanan. Thread Compositor dan raster juga berjalan di dalam proses perender untuk merender halaman secara efisien dan lancar.
Tugas inti proses perender adalah mengubah HTML, CSS, dan JavaScript menjadi halaman web yang dapat berinteraksi dengan pengguna.
Penguraian
Konstruksi DOM
Saat proses perender menerima pesan commit untuk navigasi dan mulai menerima data HTML, thread utama akan mulai mengurai string teks (HTML) dan mengubahnya menjadi Document Object Model (DOM).
DOM adalah representasi internal halaman dari browser, serta struktur data dan API yang dapat berinteraksi dengan developer web melalui JavaScript.
Mengurai dokumen HTML ke dalam DOM ditentukan oleh Standar HTML. Anda mungkin telah memperhatikan bahwa memasukkan HTML ke browser tidak pernah menampilkan error. Misalnya, tag </p>
penutup yang tidak ada adalah HTML yang valid. Markup yang salah seperti Hi! <b>I'm <i>Chrome</b>!</i>
(tag b ditutup sebelum tag i) diperlakukan seolah-olah Anda menulis Hi! <b>I'm <i>Chrome</i></b><i>!</i>
. Hal ini karena spesifikasi HTML didesain untuk menangani error tersebut dengan baik. Jika ingin tahu bagaimana hal-hal ini dilakukan, Anda dapat membaca
bagian "Pengantar penanganan error dan kasus aneh di parser"
pada spesifikasi HTML.
Memuat subresource
{i>Website<i} biasanya menggunakan sumber daya eksternal seperti gambar, CSS, dan JavaScript. File-file tersebut perlu
dimuat dari jaringan atau cache. Thread utama dapat memintanya satu per satu saat menemukannya
saat mengurai untuk membangun DOM, tetapi untuk mempercepat, "pemindai pramuat" dijalankan secara serentak.
Jika ada hal seperti <img>
atau <link>
di dokumen HTML, pemindai pramuat akan mengintip token
yang dihasilkan oleh parser HTML dan mengirimkan permintaan ke thread jaringan dalam proses browser.
JavaScript dapat memblokir penguraian
Saat menemukan tag <script>
, parser HTML akan menjeda penguraian dokumen HTML dan harus
memuat, mengurai, dan mengeksekusi kode JavaScript. Mengapa? karena JavaScript dapat mengubah bentuk
dokumen menggunakan hal-hal seperti document.write()
yang mengubah seluruh struktur DOM (ringkasan model penguraian
dalam spesifikasi HTML memiliki diagram yang bagus). Inilah alasan parser HTML harus menunggu JavaScript
berjalan sebelum dapat melanjutkan penguraian dokumen HTML. Jika Anda ingin mengetahui apa yang terjadi dalam
eksekusi JavaScript, tim V8 mengadakan diskusi dan postingan blog mengenai hal ini.
Petunjuk ke browser cara Anda ingin memuat resource
Ada banyak cara yang dapat digunakan developer web untuk mengirimkan petunjuk ke browser untuk memuat resource dengan baik.
Jika JavaScript tidak menggunakan document.write()
, Anda dapat menambahkan atribut async
atau defer
ke tag <script>
. Selanjutnya, browser akan memuat dan menjalankan kode JavaScript secara asinkron dan tidak memblokir penguraian. Anda juga dapat menggunakan modul JavaScript jika sesuai. <link rel="preload">
adalah cara untuk memberi tahu browser bahwa resource benar-benar diperlukan untuk navigasi saat ini dan Anda ingin mendownloadnya sesegera mungkin. Anda dapat membaca selengkapnya tentang hal ini di Prioritrasi Resource – Mendapatkan Browser untuk Membantu Anda.
Penghitungan gaya
Memiliki DOM tidak cukup untuk mengetahui tampilan halaman, karena kita dapat menata gaya elemen halaman dalam CSS. Thread utama mengurai CSS dan menentukan gaya yang dihitung untuk setiap node DOM. Ini adalah
informasi tentang jenis gaya yang diterapkan pada setiap elemen berdasarkan pemilih CSS. Anda dapat melihat
informasi ini di bagian computed
DevTools.
Bahkan jika Anda tidak memberikan CSS, setiap simpul DOM memiliki gaya yang dihitung. Tag <h1>
ditampilkan
lebih besar dari tag <h2>
dan margin ditentukan untuk setiap elemen. Hal ini dikarenakan browser memiliki
{i>style sheet<i} default. Jika ingin mengetahui tampilan CSS default Chrome,
Anda dapat melihat kode sumbernya di sini.
Tata Letak
Sekarang proses perender mengetahui struktur dokumen dan gaya untuk setiap node, tetapi hal tersebut tidak cukup untuk merender halaman. Bayangkan Anda sedang mencoba mendeskripsikan sebuah lukisan kepada teman Anda melalui telepon. "Ada lingkaran merah besar dan kotak biru kecil" tidak memberikan informasi yang cukup bagi teman Anda untuk mengetahui seperti apa tampilan lukisan itu.
Tata letak adalah proses untuk menemukan geometri elemen. Thread utama berjalan melalui DOM dan gaya terkomputasi, lalu membuat hierarki tata letak yang memiliki informasi seperti koordinat x y dan ukuran kotak pembatas. Hierarki tata letak mungkin mirip dengan struktur hierarki DOM, tetapi hanya berisi informasi
yang terkait dengan yang terlihat di halaman. Jika display: none
diterapkan, elemen tersebut bukan bagian dari
hierarki tata letak (namun, elemen dengan visibility: hidden
ada dalam hierarki tata letak). Demikian pula,
jika elemen pseudo dengan konten seperti p::before{content:"Hi!"}
diterapkan, elemen tersebut akan disertakan dalam
hierarki tata letak meskipun tidak ada dalam DOM.
Menentukan Tata Letak halaman adalah tugas yang menantang. Bahkan tata letak halaman yang paling sederhana seperti blok yang mengalir dari atas ke bawah juga harus mempertimbangkan seberapa besar font dan di mana harus memisahkan baris karena hal itu memengaruhi ukuran dan bentuk paragraf; yang kemudian memengaruhi posisi paragraf berikutnya.
CSS dapat membuat elemen mengapung ke satu sisi, menyamarkan item tambahan, dan mengubah arah penulisan. Bisa Anda bayangkan, tahap tata letak ini memiliki tugas yang luar biasa. Di Chrome, seluruh tim insinyur mengerjakan tata letak. Jika Anda ingin melihat detail pekerjaan mereka, beberapa diskusi dari BlinkOn Conference akan direkam dan cukup menarik untuk ditonton.
Cat
Memiliki DOM, gaya, dan tata letak masih belum cukup untuk merender halaman. Katakanlah Anda sedang mencoba mereproduksi sebuah lukisan. Anda mengetahui ukuran, bentuk, dan lokasi elemen, tetapi Anda masih harus menilai urutan Anda dalam melukisnya.
Misalnya, z-index
mungkin ditetapkan untuk elemen tertentu. Dalam hal ini, menggambar sesuai urutan elemen yang ditulis dalam HTML akan menyebabkan rendering yang salah.
Pada langkah paint ini, thread utama akan menelusuri hierarki tata letak untuk membuat kumpulan data cat. Catatan cat adalah
catatan proses pengecatan seperti "latar belakang terlebih dahulu, lalu teks, lalu persegi panjang". Jika Anda telah menggambar pada
elemen <canvas>
menggunakan JavaScript, proses ini mungkin tidak asing bagi Anda.
Mengupdate pipeline rendering memerlukan banyak biaya
Hal terpenting yang perlu dipahami dalam pipeline rendering adalah pada setiap langkah, hasil dari operasi sebelumnya akan digunakan untuk membuat data baru. Misalnya, jika ada perubahan di hierarki tata letak, urutan Paint harus dibuat ulang untuk bagian dokumen yang terpengaruh.
Jika Anda menganimasikan elemen, browser harus menjalankan operasi ini di antara setiap bingkai. Sebagian besar layar kami memuat ulang layar 60 kali per detik (60 fps); animasi akan tampak halus di mata manusia saat Anda menggerakkan objek di layar pada setiap frame. Namun, jika animasi melewatkan frame di antaranya, halaman akan muncul "jank".
Meskipun operasi rendering Anda mengikuti muat ulang layar, penghitungan ini berjalan di thread utama, yang berarti penghitungan ini dapat diblokir saat aplikasi Anda menjalankan JavaScript.
Anda dapat membagi operasi JavaScript menjadi potongan-potongan kecil dan jadwal untuk dijalankan di setiap frame menggunakan
requestAnimationFrame()
. Untuk informasi selengkapnya tentang topik ini, lihat
Mengoptimalkan Eksekusi JavaScript
. Anda juga dapat menjalankan JavaScript di Web Worker
untuk menghindari pemblokiran thread utama.
Pengomposisian
Bagaimana Anda akan menggambar sebuah halaman?
Setelah browser mengetahui struktur dokumen, gaya setiap elemen, geometri halaman, dan urutan cat, bagaimana cara menggambar halaman? Mengubah informasi ini menjadi {i>pixel<i} di layar disebut rasterisasi.
Mungkin cara naif untuk menangani ini adalah dengan melakukan raster pada bagian di dalam area pandang. Jika pengguna men-scroll halaman, lalu memindahkan frame raster, dan mengisi bagian yang hilang dengan melakukan raster lagi. Berikut adalah cara Chrome menangani proses raster saat pertama kali dirilis. Namun, browser modern menjalankan proses yang lebih canggih yang disebut pengomposisian.
Apa itu pengomposisian
Pengomposisian adalah teknik untuk memisahkan bagian halaman menjadi lapisan, merasternya secara terpisah, dan menggabungkan sebagai halaman dalam thread terpisah yang disebut thread compositor. Jika scroll terjadi, karena lapisan sudah diraster, yang perlu dilakukan hanyalah menyusun frame baru. Animasi dapat dilakukan dengan cara yang sama dengan memindahkan lapisan dan menyusun frame baru.
Anda dapat melihat bagaimana situs dibagi menjadi beberapa lapisan di DevTools menggunakan panel Lapisan.
Membagi menjadi beberapa lapisan
Untuk mengetahui elemen mana yang perlu berada di lapisan mana, thread utama berjalan melalui
hierarki tata letak untuk membuat hierarki lapisan (bagian ini disebut "Update Layer Tree" di panel
performa DevTools). Jika bagian tertentu dari halaman yang seharusnya berupa lapisan terpisah (seperti menu samping
slide-in) tidak mendapatkannya, Anda dapat memberi petunjuk ke browser dengan menggunakan atribut will-change
di CSS.
Anda mungkin tergoda untuk memberikan lapisan ke setiap elemen, tetapi pengomposisian di antara lapisan yang berlebihan dapat menyebabkan operasi yang lebih lambat daripada meraster bagian kecil dari setiap frame. Oleh karena itu, penting bagi Anda untuk mengukur performa rendering aplikasi. Untuk informasi selengkapnya tentang topik ini, lihat Berpegang pada Properti Khusus Compositor dan Mengelola Jumlah Lapisan.
Raster dan komposit dari thread utama
Setelah hierarki lapisan dibuat dan urutan pewarnaan ditentukan, thread utama meng-commit informasi tersebut ke thread compositor. Thread compositor kemudian merasterisasi setiap lapisan. Lapisan bisa berukuran besar seperti keseluruhan panjang halaman, sehingga thread compositor membaginya menjadi kartu dan mengirimkan setiap kartu ke thread raster. Thread raster me-raster setiap kartu dan menyimpannya di memori GPU.
Thread compositor dapat memprioritaskan thread raster yang berbeda sehingga objek dalam area pandang (atau terdekat) dapat diraster terlebih dahulu. Lapisan juga memiliki beberapa ubin untuk resolusi yang berbeda guna menangani hal-hal seperti tindakan zoom-in.
Setelah kartu diraster, thread compositor mengumpulkan informasi kartu yang disebut gambar segi empat untuk membuat frame compositor.
Menggambar segi empat | Berisi informasi seperti lokasi kartu di memori dan tempat menggambar kartu dengan mempertimbangkan komposisi halaman. |
Frame Compositor | Kumpulan kuadrat gambar yang mewakili bingkai halaman. |
Sebuah {i>frame<i} compositor kemudian dikirimkan ke proses {i>browser<i} melalui IPC. Pada tahap ini, frame compositor lain dapat ditambahkan dari UI thread untuk perubahan UI browser atau dari proses perender lainnya untuk ekstensi. Frame compositor ini dikirim ke GPU untuk menampilkannya di layar. Jika peristiwa scroll masuk, thread compositor akan membuat frame compositor lain untuk dikirim ke GPU.
Manfaat pengomposisian adalah dapat dilakukan tanpa melibatkan thread utama. Thread Compositor tidak perlu menunggu penghitungan gaya atau eksekusi JavaScript. Inilah alasan mengomposisikan animasi saja dianggap paling baik untuk performa yang lancar. Jika tata letak atau paint perlu dihitung lagi, thread utama harus dilibatkan.
Penutup
Dalam postingan ini, kita melihat pipeline rendering dari penguraian hingga pengomposisian. Semoga sekarang Anda lebih mampu untuk membaca lebih lanjut tentang pengoptimalan performa situs.
Pada postingan berikutnya dan terakhir dalam rangkaian ini, kita akan membahas thread compositor secara lebih detail dan
melihat apa yang terjadi saat input pengguna seperti mouse move
dan click
masuk.
Apakah Anda menyukai postingan ini? Jika ada pertanyaan atau saran untuk postingan mendatang, kami ingin mendengar pendapat Anda di bagian komentar di bawah atau @kosamari di Twitter.