Pemuatan resource Optimize

Dalam modul sebelumnya, beberapa teori di balik jalur rendering penting dieksplorasi, dan bagaimana resource pemblokiran render dan pemblokir parser dapat menunda rendering awal halaman. Setelah memahami beberapa teori di balik hal ini, Anda siap untuk mempelajari beberapa teknik untuk mengoptimalkan jalur rendering penting.

Saat halaman dimuat, banyak resource yang direferensikan dalam HTML-nya menyediakan halaman beserta tampilan dan tata letaknya melalui CSS, serta interaktivitasnya melalui JavaScript. Dalam modul ini, sejumlah konsep penting yang terkait dengan resource ini dan pengaruhnya terhadap waktu pemuatan halaman akan dibahas.

Pemblokiran rendering

Seperti yang telah dibahas dalam modul sebelumnya, CSS adalah resource pemblokiran render, karena memblokir browser agar tidak merender konten apa pun hingga Model Objek CSS (CSSOM) dibuat. Browser memblokir rendering untuk mencegah Flash of Unstyled Content (FOUC), yang tidak diinginkan dari sudut pandang pengalaman pengguna.

Dalam video sebelumnya, ada FOUC singkat tempat Anda dapat melihat halaman tanpa gaya apa pun. Selanjutnya, semua gaya akan diterapkan setelah CSS halaman selesai dimuat dari jaringan, dan versi halaman yang tidak bergaya akan segera diganti dengan versi yang telah diberi gaya.

Secara umum, FOUC adalah sesuatu yang biasanya tidak Anda lihat, tetapi konsep ini penting untuk dipahami agar Anda mengetahui alasan browser memblokir rendering halaman hingga CSS didownload dan diterapkan ke halaman. Pemblokiran rendering bukannya tidak diinginkan, tetapi Anda ingin meminimalkan durasinya dengan menjaga agar CSS Anda tetap optimal.

Pemblokiran parser

Resource pemblokiran parser mengganggu parser HTML, seperti elemen <script> tanpa atribut async atau defer. Saat parser menemukan elemen <script>, browser harus mengevaluasi dan mengeksekusi skrip sebelum melanjutkan dengan mengurai seluruh HTML. Hal ini sudah dirancang karena skrip dapat mengubah atau mengakses DOM selama waktu ketika DOM masih dibuat.

<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>

Saat menggunakan file JavaScript eksternal (tanpa async atau defer), parser akan diblokir dari saat file ditemukan hingga file didownload, diuraikan, dan dieksekusi. Saat menggunakan JavaScript inline, parser akan diblokir juga hingga skrip inline diurai dan dieksekusi.

Pemindai pramuat

Pemindai pramuat adalah pengoptimalan browser dalam bentuk parser HTML sekunder yang memindai respons HTML mentah untuk menemukan dan mengambil resource secara spekulatif sebelum parser HTML utama menemukannya. Misalnya, pemindai pramuat akan memungkinkan browser mulai mendownload resource yang ditentukan dalam elemen <img>, meskipun parser HTML diblokir saat mengambil dan memproses resource seperti CSS dan JavaScript.

Untuk memanfaatkan pemindai pramuat, resource penting harus disertakan dalam markup HTML yang dikirim oleh server. Pola pemuatan resource berikut tidak dapat ditemukan oleh pemindai pramuat:

  • Gambar yang dimuat oleh CSS menggunakan properti background-image. Referensi gambar ini berada dalam CSS, dan tidak dapat ditemukan oleh pemindai pramuat.
  • Skrip yang dimuat secara dinamis dalam bentuk markup elemen <script> yang dimasukkan ke DOM menggunakan JavaScript atau modul yang dimuat menggunakan import() dinamis.
  • HTML yang dirender pada klien menggunakan JavaScript. Markup tersebut terdapat dalam string di resource JavaScript, dan tidak dapat ditemukan oleh pemindai pramuat.
  • Deklarasi @import CSS.

Semua pola pemuatan resource ini adalah resource yang terlambat ditemukan, sehingga tidak mendapatkan manfaat dari pemindai pramuat. Hindari hal ini jika memungkinkan. Namun, jika menghindari pola tersebut tidak memungkinkan, Anda mungkin dapat menggunakan petunjuk preload untuk menghindari penundaan penemuan resource.

CSS

CSS menentukan presentasi dan tata letak halaman. Seperti yang dijelaskan sebelumnya, CSS adalah resource pemblokir render, sehingga pengoptimalan CSS dapat berdampak besar terhadap waktu muat halaman secara keseluruhan.

Minifikasi

Meminifikasi file CSS akan mengurangi ukuran file resource CSS, sehingga membuatnya lebih cepat didownload. Hal ini terutama dicapai dengan menghapus konten dari file CSS sumber, seperti spasi dan karakter tak terlihat lainnya, serta meng-output hasilnya ke file yang baru dioptimalkan:

/* Unminified CSS: */

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

Dalam bentuknya yang paling dasar, minifikasi CSS adalah pengoptimalan efektif yang dapat meningkatkan FCP situs Anda, dan bahkan mungkin LCP dalam beberapa kasus. Alat seperti bundler dapat otomatis melakukan pengoptimalan ini untuk Anda dalam build produksi.

Hapus CSS yang tidak digunakan

Sebelum merender konten apa pun, browser harus mendownload dan mengurai semua style sheet. Waktu yang diperlukan untuk menyelesaikan penguraian juga mencakup gaya yang tidak digunakan di halaman saat ini. Jika Anda menggunakan bundler yang menggabungkan semua resource CSS menjadi satu file, pengguna Anda mungkin akan mendownload lebih banyak CSS daripada yang diperlukan untuk merender halaman saat ini.

Untuk menemukan CSS yang tidak digunakan untuk halaman saat ini, gunakan Alat cakupan di Chrome DevTools.

Screenshot alat cakupan di Chrome DevTools. File CSS dipilih di panel bawah, menunjukkan sejumlah besar CSS yang tidak digunakan oleh tata letak halaman saat ini.
Alat cakupan di Chrome DevTools berguna untuk mendeteksi CSS (dan JavaScript) yang tidak digunakan oleh halaman saat ini. CSS ini dapat digunakan untuk membagi file CSS menjadi beberapa resource untuk dimuat oleh halaman yang berbeda, bukan mengirimkan paket CSS yang jauh lebih besar yang dapat menunda rendering halaman.

Menghapus CSS yang tidak digunakan memiliki efek dua kali lipat: selain mengurangi waktu download, Anda juga mengoptimalkan konstruksi hierarki render, karena browser perlu memproses lebih sedikit aturan CSS.

Menghindari deklarasi @import CSS

Meskipun mungkin terlihat nyaman, Anda harus menghindari deklarasi @import di CSS:

/* Don't do this: */
@import url('style.css');

Demikian pula dengan cara kerja elemen <link> di HTML, deklarasi @import di CSS memungkinkan Anda mengimpor resource CSS eksternal dari dalam style sheet. Perbedaan utama antara kedua pendekatan ini adalah bahwa elemen <link> HTML adalah bagian dari respons HTML, dan oleh karena itu ditemukan jauh lebih cepat daripada file CSS yang didownload oleh deklarasi @import.

Alasannya adalah agar deklarasi @import dapat ditemukan, file CSS yang memuatnya harus terlebih dahulu didownload. Hal ini mengakibatkan apa yang dikenal sebagai rantai permintaan, yang—dalam kasus CSS—menunda waktu yang diperlukan untuk merender halaman pertama kali. Kekurangan lainnya adalah style sheet yang dimuat menggunakan deklarasi @import tidak dapat ditemukan oleh pemindai pramuat, sehingga menjadi resource pemblokir render yang terlambat ditemukan.

<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">

Pada umumnya, Anda dapat mengganti @import menggunakan elemen <link rel="stylesheet">. Elemen <link> memungkinkan style sheet didownload secara serentak dan mengurangi waktu pemuatan keseluruhan, bukan deklarasi @import, yang mendownload style sheet secara berurutan.

CSS kritis inline

Waktu yang diperlukan untuk mendownload file CSS dapat meningkatkan FCP halaman. Memasukkan gaya penting dalam <head> dokumen akan menghilangkan permintaan jaringan untuk resource CSS, dan—jika dilakukan dengan benar—dapat memperbaiki waktu pemuatan awal saat cache browser pengguna tidak disiapkan. CSS yang tersisa dapat dimuat secara asinkron, atau ditambahkan di akhir elemen <body>.

<head>
  <title>Page Title</title>
  <!-- ... -->
  <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
  <!-- Other page markup... -->
  <link rel="stylesheet" href="non-critical.css">
</body>

Kelemahannya, menyisipkan sejumlah besar CSS akan menambah lebih banyak byte ke respons HTML awal. Karena resource HTML sering kali tidak bisa di-cache untuk waktu yang lama—atau sama sekali—ini berarti CSS inline tidak di-cache untuk halaman berikutnya yang mungkin menggunakan CSS yang sama di style sheet eksternal. Uji dan ukur performa halaman Anda untuk memastikan komprominya sepadan dengan usaha Anda.

Demo CSS

JavaScript

JavaScript mendorong sebagian besar interaktivitas di web, tetapi hal ini menimbulkan biaya. Mengirimkan terlalu banyak JavaScript dapat membuat halaman web Anda lambat merespons selama pemuatan halaman, dan bahkan dapat menyebabkan masalah responsivitas yang memperlambat interaksi—keduanya dapat menjengkelkan bagi pengguna.

JavaScript yang memblokir perenderan

Saat memuat elemen <script> tanpa atribut defer atau async, browser akan memblokir penguraian dan rendering hingga skrip didownload, diurai, dan dijalankan. Demikian pula, skrip inline memblokir parser hingga skrip diuraikan dan dieksekusi.

async versus defer

async dan defer memungkinkan skrip eksternal dimuat tanpa memblokir parser HTML sementara skrip (termasuk skrip inline) dengan type="module" ditangguhkan secara otomatis. Namun, async dan defer memiliki beberapa perbedaan yang penting untuk dipahami.

Penggambaran berbagai mekanisme pemuatan skrip, semuanya menjelaskan peran parser, pengambilan, dan eksekusi berdasarkan berbagai atribut yang digunakan seperti async, hold, type=&#39;module&#39;, dan kombinasi dari ketiganya.
Bersumber dari https://html.spec.whatwg.org/multipage/scripting.html

Skrip yang dimuat dengan async akan segera diuraikan dan dijalankan setelah didownload, sedangkan skrip yang dimuat dengan defer akan dijalankan saat penguraian dokumen HTML selesai—hal ini terjadi bersamaan dengan peristiwa DOMContentLoaded browser. Selain itu, skrip async dapat dijalankan secara tidak berurutan, sedangkan skrip defer dijalankan sesuai urutan kemunculannya di markup.

Rendering sisi klien

Umumnya, sebaiknya hindari penggunaan JavaScript untuk merender konten penting atau elemen LCP halaman. Hal ini dikenal sebagai rendering sisi klien, dan merupakan teknik yang digunakan secara ekstensif dalam Aplikasi Web Satu Halaman (SPA).

Markup yang dirender oleh JavaScript menggantikan pemindai pramuat, karena resource yang terdapat dalam markup yang dirender klien tidak dapat ditemukan olehnya. Hal ini dapat menunda download resource penting, seperti gambar LCP. Browser hanya akan mulai mendownload gambar LCP setelah skrip dieksekusi, dan menambahkan elemen tersebut ke DOM. Oleh karena itu, skrip hanya dapat dijalankan setelah ditemukan, didownload, dan diurai. Hal ini dikenal sebagai rantai permintaan penting dan harus dihindari.

Selain itu, markup rendering menggunakan JavaScript lebih mungkin menghasilkan tugas panjang daripada markup yang didownload dari server sebagai respons terhadap permintaan navigasi. Penggunaan rendering HTML sisi klien yang ekstensif dapat berdampak negatif pada latensi interaksi. Hal ini terjadi terutama jika DOM halaman sangat besar, yang memicu pekerjaan rendering signifikan saat JavaScript mengubah DOM.

Minifikasi

Serupa dengan CSS, meminimalkan JavaScript akan mengurangi ukuran file resource skrip. Hal ini dapat menghasilkan download yang lebih cepat, sehingga browser dapat berpindah ke proses penguraian dan kompilasi JavaScript dengan lebih cepat.

Selain itu, minifikasi JavaScript selangkah lebih maju daripada mengecilkan aset lain, seperti CSS. Saat JavaScript diminifikasi, JavaScript tidak hanya dihilangkan dari hal-hal seperti spasi, tab, dan komentar, tetapi simbol dalam JavaScript sumber dipersingkat. Proses ini terkadang dikenal sebagai uglifikasi. Untuk melihat perbedaannya, ambil kode sumber JavaScript berikut:

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}

Jika kode sumber JavaScript sebelumnya tidak jelas, hasilnya mungkin akan terlihat seperti cuplikan kode berikut:

// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

Dalam cuplikan sebelumnya, Anda dapat melihat bahwa variabel scriptElement yang dapat dibaca manusia dalam sumber disingkat menjadi t. Jika diterapkan di seluruh koleksi skrip yang besar, penghematan bisa sangat signifikan, tanpa memengaruhi fitur yang disediakan JavaScript produksi situs.

Jika Anda menggunakan bundler untuk memproses kode sumber situs web Anda, uglifikasi sering kali dilakukan secara otomatis untuk build produksi. Uglifier—seperti Terser, misalnya—juga sangat mudah dikonfigurasi, sehingga Anda dapat menyesuaikan agresivitas algoritme uglification untuk mencapai penghematan maksimum. Namun, setelan default untuk setiap alat penghapusan biasanya cukup untuk mencapai keseimbangan yang tepat antara ukuran output dan mempertahankan kemampuan.

Demo JavaScript

Menguji pengetahuan Anda

Apa cara terbaik untuk memuat beberapa file CSS di browser?

Deklarasi @import CSS.
Coba lagi.
Beberapa elemen <link>.
Benar.

Apa yang dilakukan pemindai pramuat browser?

Ini adalah parser HTML sekunder yang memeriksa markup mentah untuk menemukan resource sebelum parser DOM dapat menemukannya lebih cepat.
Benar.
Mendeteksi elemen <link rel="preload"> di resource HTML.
Coba lagi.

Mengapa browser memblokir sementara penguraian HTML secara default saat mendownload resource JavaScript?

Untuk mencegah Flash Konten Tanpa Gaya (FOUC).
Coba lagi.
Karena mengevaluasi JavaScript adalah tugas yang sangat menghabiskan banyak CPU, dan menjeda penguraian HTML akan memberikan lebih banyak bandwidth ke CPU untuk menyelesaikan pemuatan skrip.
Coba lagi.
Karena skrip dapat memodifikasi atau mengakses DOM.
Benar.

Berikutnya: Membantu browser dengan petunjuk resource

Setelah Anda memahami bagaimana resource yang dimuat dalam elemen <head> dapat memengaruhi pemuatan halaman awal dan berbagai metrik, sekarang saatnya untuk melanjutkan. Dalam modul berikutnya, kita akan mempelajari petunjuk resource, dan bagaimana keduanya dapat memberikan petunjuk berharga bagi browser untuk mulai memuat resource dan membuka koneksi ke server lintas-asal lebih cepat daripada browser tanpa izin tersebut.