Cara kerja internal Proses Perender
Artikel ini adalah bagian 3 dari seri blog 4 bagian 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 di Dasar-Dasar Web memiliki lebih banyak referensi.
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 JavaScript Anda ditangani oleh thread pekerja jika Anda menggunakan pekerja web atau pekerja layanan. Thread raster dan kompositor juga dijalankan 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 digunakan pengguna untuk berinteraksi.

Penguraian
Pembuatan DOM
Saat proses perender menerima pesan commit untuk navigasi dan mulai menerima data HTML, thread utama mulai mengurai string teks (HTML) dan mengubahnya menjadi Document Object Model (DOM).
DOM adalah representasi internal halaman browser serta struktur data dan API yang dapat berinteraksi dengan developer web melalui JavaScript.
Mengurai dokumen HTML menjadi 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 dirancang untuk
menangani error tersebut dengan baik. Jika ingin mengetahui cara melakukannya, Anda dapat membaca bagian
"Pengantar penanganan error dan kasus aneh dalam parser"
di spesifikasi HTML.
Pemuatan subresource
Situs biasanya menggunakan resource eksternal seperti gambar, CSS, dan JavaScript. File tersebut perlu
dimuat dari jaringan atau cache. Thread utama dapat memintanya satu per satu saat menemukannya
saat mengurai untuk membuat DOM, tetapi untuk mempercepat, "pemindai pramuat" dijalankan secara serentak.
Jika ada hal-hal seperti <img>
atau <link>
dalam dokumen HTML, pemindai pramuat akan melihat token
yang dihasilkan oleh parser HTML dan mengirim 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 sebabnya parser HTML harus menunggu JavaScript
berjalan sebelum dapat melanjutkan penguraian dokumen HTML. Jika Anda ingin tahu apa yang terjadi dalam
eksekusi JavaScript, tim V8 memiliki presentasi dan postingan blog tentang hal ini.
Memberi petunjuk kepada browser tentang cara Anda ingin memuat resource
Ada banyak cara yang dapat dilakukan developer web untuk mengirim petunjuk ke browser agar memuat resource dengan baik.
Jika JavaScript tidak menggunakan document.write()
, Anda dapat menambahkan atribut async
atau defer
ke tag <script>
. Kemudian, browser 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 tersebut sangat diperlukan untuk navigasi saat ini dan Anda ingin mendownloadnya sesegera mungkin. Anda dapat membaca selengkapnya tentang hal ini di Prioritas Aset – Membuat Browser Membantu Anda.
Penghitungan gaya
Memiliki DOM saja tidak cukup untuk mengetahui tampilan halaman karena kita dapat menata gaya elemen halaman
di CSS. Thread utama mengurai CSS dan menentukan gaya yang dihitung untuk setiap node DOM. Ini adalah
informasi tentang jenis gaya yang diterapkan ke setiap elemen berdasarkan pemilih CSS. Anda dapat melihat informasi ini di bagian computed
DevTools.

Meskipun Anda tidak menyediakan CSS, setiap node DOM memiliki gaya yang dihitung. Tag <h1>
ditampilkan
lebih besar dari tag <h2>
dan margin ditentukan untuk setiap elemen. Hal ini karena browser memiliki
lembar gaya default. Jika ingin mengetahui seperti apa 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 itu tidak cukup untuk merender halaman. Bayangkan Anda mencoba menjelaskan sebuah lukisan kepada teman melalui ponsel. "Ada lingkaran merah besar dan kotak biru kecil" bukanlah informasi yang cukup bagi teman Anda untuk mengetahui seperti apa lukisan itu.

Tata letak adalah proses untuk menemukan geometri elemen. Thread utama menelusuri DOM dan
gaya yang dihitung serta membuat hierarki tata letak yang memiliki informasi seperti koordinat x y dan ukuran
kotak pembatas. Hierarki tata letak mungkin memiliki struktur yang mirip dengan hierarki DOM, tetapi hanya berisi informasi
yang terkait dengan apa yang terlihat di halaman. Jika display: none
diterapkan, elemen tersebut bukan bagian dari
hierarki tata letak (tetapi, 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 di DOM.

Menentukan Tata letak halaman adalah tugas yang menantang. Bahkan tata letak halaman yang paling sederhana seperti alur blok dari atas ke bawah harus mempertimbangkan ukuran font dan tempat untuk membuat baris baru karena hal tersebut memengaruhi ukuran dan bentuk paragraf; yang kemudian memengaruhi tempat paragraf berikutnya harus berada.
CSS dapat membuat elemen mengapung ke satu sisi, menyamarkan item tambahan, dan mengubah arah penulisan. Anda dapat membayangkan, tahap tata letak ini memiliki tugas yang berat. Di Chrome, seluruh tim engineer mengerjakan tata letak. Jika Anda ingin melihat detail pekerjaan mereka, beberapa presentasi dari BlinkOn Conference direkam dan cukup menarik untuk ditonton.
Cat

Memiliki DOM, gaya, dan tata letak masih belum cukup untuk merender halaman. Misalnya, Anda mencoba mereproduksi lukisan. Anda tahu ukuran, bentuk, dan lokasi elemen, tetapi Anda masih harus menilai urutan untuk melukisnya.
Misalnya, z-index
mungkin ditetapkan untuk elemen tertentu, dalam hal ini, menggambar dalam urutan
elemen yang ditulis dalam HTML akan menghasilkan rendering yang salah.

Pada langkah gambar ini, thread utama menelusuri hierarki tata letak untuk membuat data gambar. Data 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 sudah tidak asing bagi Anda.

Memperbarui pipeline rendering membutuhkan biaya yang mahal
Hal terpenting yang harus dipahami dalam pipeline rendering adalah pada setiap langkah, hasil operasi sebelumnya digunakan untuk membuat data baru. Misalnya, jika ada perubahan dalam hierarki tata letak, urutan Paint perlu dibuat ulang untuk bagian dokumen yang terpengaruh.
Jika Anda menganimasikan elemen, browser harus menjalankan operasi ini di antara setiap frame. Sebagian besar layar kami memuat ulang layar 60 kali per detik (60 fps); animasi akan tampak halus bagi mata manusia saat Anda memindahkan sesuatu di layar pada setiap frame. Namun, jika animasi melewatkan frame di antaranya, halaman akan tampak "janggal".

Meskipun operasi rendering Anda mengikuti refresh layar, penghitungan ini berjalan di thread utama, yang berarti dapat diblokir saat aplikasi Anda menjalankan JavaScript.

Anda dapat membagi operasi JavaScript menjadi beberapa bagian kecil dan menjadwalkan untuk dijalankan di setiap frame menggunakan
requestAnimationFrame()
. Untuk mengetahui informasi selengkapnya tentang topik ini, lihat
Mengoptimalkan Eksekusi JavaScript
. Anda juga dapat menjalankan JavaScript di Web Worker
untuk menghindari pemblokiran thread utama.

Komposisi
Bagaimana cara Anda menggambar halaman?
Setelah browser mengetahui struktur dokumen, gaya setiap elemen, geometri halaman, dan urutan gambar, bagaimana cara browser menggambar halaman? Mengubah informasi ini menjadi piksel di layar disebut rasterisasi.
Mungkin cara sederhana untuk menangani hal ini adalah dengan meraster bagian di dalam area pandang. Jika pengguna men-scroll halaman, pindahkan bingkai raster, dan isi bagian yang hilang dengan melakukan raster lebih banyak. Ini adalah cara Chrome menangani rasterisasi saat pertama kali dirilis. Namun, browser modern menjalankan proses yang lebih canggih yang disebut komposisi.
Apa yang dimaksud dengan komposisi
Komposisi adalah teknik untuk memisahkan bagian halaman menjadi beberapa lapisan, merasterisasinya secara terpisah, dan membuat komposisi sebagai halaman dalam thread terpisah yang disebut thread kompositor. Jika scroll terjadi, karena lapisan sudah dirasterisasi, yang harus dilakukan hanyalah menggabungkan frame baru. Animasi dapat dicapai dengan cara yang sama dengan memindahkan lapisan dan menggabungkan frame baru.
Anda dapat melihat cara situs Anda dibagi menjadi beberapa lapisan di DevTools menggunakan panel Lapisan.
Membagi menjadi beberapa lapisan
Untuk mengetahui elemen mana yang harus berada di lapisan mana, thread utama akan menelusuri
hierarki tata letak untuk membuat hierarki lapisan (bagian ini disebut "Update Layer Tree" di panel
performa DevTools). Jika bagian tertentu dari halaman yang seharusnya merupakan lapisan terpisah (seperti menu samping
slide-in) tidak mendapatkannya, Anda dapat memberikan petunjuk ke browser menggunakan atribut will-change
di CSS.

Anda mungkin tergoda untuk memberikan lapisan ke setiap elemen, tetapi pengomposisian di seluruh lapisan yang berlebih dapat menyebabkan operasi yang lebih lambat daripada merasterisasi bagian kecil halaman setiap frame, sehingga Anda harus mengukur performa rendering aplikasi. Untuk mengetahui informasi selengkapnya tentang topik ini, lihat Menggunakan Properti Khusus Compositor dan Mengelola Jumlah Lapisan.
Raster dan gabungan dari thread utama
Setelah hierarki lapisan dibuat dan urutan gambar ditentukan, thread utama akan meng-commit informasi tersebut ke thread kompositor. Thread kompositor kemudian merasterisasi setiap lapisan. Lapisan dapat berukuran besar seperti seluruh panjang halaman, sehingga thread kompositor membaginya menjadi ubin dan mengirim setiap ubin ke thread raster. Thread raster merasterisasi setiap ubin dan menyimpannya di memori GPU.

Thread kompositor dapat memprioritaskan thread raster yang berbeda sehingga hal-hal dalam area pandang (atau di dekatnya) dapat diraster terlebih dahulu. Lapisan juga memiliki beberapa ubin untuk resolusi yang berbeda guna menangani hal-hal seperti tindakan zoom in.
Setelah ubin diraster, thread komposer mengumpulkan informasi ubin yang disebut draw quads untuk membuat frame komposer.
Menggambar kuadrat | Berisi informasi seperti lokasi kartu di memori dan tempat di halaman untuk menggambar kartu dengan mempertimbangkan komposisi halaman. |
Frame kompositor | Kumpulan kuad gambar yang mewakili bingkai halaman. |
Frame kompositor kemudian dikirim ke proses browser melalui IPC. Pada tahap ini, frame komponitor lain dapat ditambahkan dari UI thread untuk perubahan UI browser atau dari proses perender lain untuk ekstensi. Frame kompositor ini dikirim ke GPU untuk menampilkannya di layar. Jika peristiwa scroll masuk, thread kompositor akan membuat frame kompositor lain untuk dikirim ke GPU.

Manfaat komposisi adalah dilakukan tanpa melibatkan thread utama. Thread komposer tidak perlu menunggu penghitungan gaya atau eksekusi JavaScript. Itulah sebabnya animasi khusus komposisi dianggap yang terbaik untuk performa yang lancar. Jika tata letak atau gambar perlu dihitung lagi, thread utama harus terlibat.
Penutup
Dalam postingan ini, kita telah melihat pipeline rendering dari penguraian hingga komposisi. Semoga sekarang Anda mampu membaca lebih lanjut tentang pengoptimalan performa situs.
Dalam postingan berikutnya dan terakhir dari seri ini, kita akan melihat thread kompositor secara lebih mendetail 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.