Mengapa website saya lambat?

In depth explanation about why your site is slow and how to fix it

Sebenarnya ini masalah klasik, sangat klasik. Ada ribuan bahkan mungkin jutaan artikel diluar sana yang membahas tentang ini, jika kamu tertarik untuk melihat dari sudut pandang yang berbeda, here we go.

Tidak seperti tulisan serupa yang diterbitkan oleh perusahaan hosting—karena kita cuma ormas yang suka buang-buang uang dan membayar pajak—tulisan ini mungkin sedikit "lower-level" dari tulisan yang sudah ada di belantara internet dan ditulis menggunakan perspektif independen.

Tulisan ini didedikasikan khusus untuk kamu, pemilik situs yang punya performa lambat. Kalau situs kamu sudah cepat, sini tunjukkin ke kita seberapa cepat sih, ha?

Latar Belakang

Koneksi internet semakin kencang, paket data semakin murah, dan high-end device semakin high dengan harga yang terjangkau. 2019 akan berakhir, dan, ya ampun website kamu masih lambat juga?

Masih menjadi misteri siapa yang harus disalahkan untuk website yang lambat. ISP kah? Perangkatmu kah? Pemilik website kah? Setan kah?

But whatever. Sebagai Super Senior Highschool CSS Engineer di evilfactorylabs, gue ingin berbagi cerita tentang alasan mengapa website lo lambat dan bikin kesel ya allah kesel banget 2019 masih ada aja website yang lambat.

Harusnya tulisan ini bermanfaat, kalau gak percaya tanya aja si raka anak itb yang suka bikin tema di themeforest. Kalau males nanya, bisa baca tulisan ini sampai habis.

Fundamental™

Kita harus tau dulu bagaimana browser bekerja browser menampilkan sesuatu setelah kita mengetik suatu alamat domain di address bar.

Ada 4 proses yang dilakukan oleh "client" (kalau pakai protokol HTTPS, jadi ada 5):

  • DNS Lookup
  • TCP Connection
  • TLS Handshake
  • Server Processing
  • Content Transfer

Yang akan kita bahas sedikit.

DNS Lookup

Ini yang paling awal, proses client (browser) mencari tau alamat IP lo. Website lo (website kita semua!) ber-alamatkan blog.evilfactory.id, dia akan bertanya dari top-level domain (.id) sampai ke resolver untuk mencari tau alamat IP dari domain tersebut.

Karena, siapa juga yang mau menghafal alamat IP dari suatu website?

Ya siapa lagi kalau bukan client, karena pada dasarnya manusia sulit untuk mengingat angka, bukan?

Disini, DNS Server yang kamu gunakan juga harus dapat diandalkan. Apakah DNS Server tersebut melakukan query sangat cepat? Apakah melakukan cache? Apakah DNS Server kamu down? Apakah DNS Server kamu cepat dijangkau?

Bagaimana cara mengetahuinya? Ya di test dong, sayang.

Bisa pakai dig(1), namebench, ataupun kombinasi time dan nslookup. Perlu diingat, client akan melakukan cache untuk query sebelumnya, untuk hasil optimal, bisa menggunakan namebench yang sudah disebutkan sebelumnya.

Proses dns query ke blog ini sekitar 5ms yang bisa dipastikan karena sudah ter-cache :)

TCP Connection

Ini adalah waktu ketika client sudah bisa berkomunikasi dengan server kamu, alias sudah dapat alamat IP kamu. Dan mencoba untuk membuka koneksi antar client-server.

Yang perlu diperhatikan disini adalah apakah servermu sibuk menghandle request yang masuk? Apakah port kamu bisa terjangkau? Karena jika ada masalah, browser akan memberikan "state" unreachable dilayar browser kamu karena servermu tidak bisa dijangkau.

TLS Handshake

Ini sesuatu yang sulit diatur "dengan tangan" oleh kita. Membahas sedikit (sedikit?) tentang ini di tulisan Bagaimana HTTPS bekerja secara teknis? Mungkin bisa baca-baca nanti kalau tertarik.

Server Processing

Namanya sudah jelas, proses disini yang perlu diperhatikan adalah:

  • Apakah servermu sibuk menghandle request yang masuk?
  • Berapa lama servermu memanggil service terhadap request yang masuk?
  • Bagaimana servermu mengatur request yang masuk?

Disini, load balancer; reverse proxy, dan keandalan service mu berperan penting. Jika menggunakan ehm hosting ataupun PaaS lain, yakinkan kalau layanan yang kamu gunakan tersebut dapat diandalkan.

Disini jika ada masalah, nanti browser akan mengirim "state" timeout ke layar browser kamu, karena browser sudah terlalu lama menunggu jawaban yang tidak pasti. ehm.

Content Transfer

Proses terakhir, akhirnya. Ini sederhana sih, tentang apa yang akan diberikan ke browser/client. Entah itu dokumen HTML, CSS, JS, JSON, Media, apapun.

Berapa lama server bisa mengirim content ke client? Ini ditingkat aplikasi/service kamu, jadi pastikan aplikasi/service kamu fast as hell dalam memberikan response.


Kita sudah membahas bagian fundamental, sekarang kita beralih ke hal-hal yang enggak fundamental-fundamental amat tapi berpengaruh. Akan kita bahas dari tingkat yang bawah sampai atas.

Round Trip

Kita akan selalu berurusan dengan latensi, tidak bisa dipungkiri lagi. Memiliki latensi sekecil mungkin adalah cara satu-satunya mengingat menghilangkan latensi adalah sesuatu yang hampir mustahil dicapai.

Yang perlu diperhatikan disini adalah:

  • Dimana DNS servermu berada?
  • Dimana servermu berada?
  • Seberapa lama aplikasi/service mu memproses request?

Seringnya kita menggunakan layanan yang menyediakan DNS Server, jadi reliabilitas kemungkinan tidak diragukan. Biasanya DNS Server provider memiliki jaringan anycast yang tersebar dibeberapa wilayah, jadi seharusnya bukan masalah yang lumayan berdampak.

Tempat dimana servermu berada sangat berpengaruh. Jika pengguna kita di Bali dan server mu berada di California, maka akan "ada sedikit waktu" untuk bisa berkomunikasi antar client-server (remember how internet works?).

Dan poin terakhir, ini yang paling penting. Meskipun DNS & Servermu berada 666m dengan client, kalau aplikasi/service mu emang lambat by design yaa akan lambat.

Mungkin dari DNS Lookup sampai Server processing hanya memakan waktu 1337ms, tapi kalau server response memakan > 5000ms yaa akan terasa lambat. Client akan liat layar blank putih dengan favicon loading.

Cache

Kita semua setuju bahwa invalidasi cache adalah hal yang paling ribet, tapi di level aplikasi web di frontend, sepertinya tidak. Client lumayan pintar dalam invalidasi cache, bisa via header Cache-control max-age, Etag, atau client-level cache via service worker.

Cache untuk asset statis bisa di-set sekitar 1 tahun, dengan catatan memenuhi kondisi seperti melakukan "versioning" untuk file tersebut dan hanya untuk file-file tertentu saja yang sekiranya frekuensi perubahannya sangat jarang.

Cache biasanya bisa di level web server/reverse proxy ataupun di aplikasi. Jadi, pergunakan fitur tersebut semaksimal mungkin.

HTTP Protocol

Kita sudah mulai ke tahap teknis-implementasi. Protokol HTTP yang kita gunakan berpengaruh terhadap performa spesifiknya di latensi. HTTP/2 menjanjikan protokol yang memiliki "lebih sedikit latensi" daripada HTTP/1.0.

Jika tertarik mempelajari tentang HTTP/2, bisa baca "buku" yang ditulis oleh pembuat cURL yang berjudul HTTP2 explained disini.

Kompresi

Ini bisa meningkatkan response time, karena data yang ditransmisi lebih kecil dari yang asli. Kompresi disini bisa menggunakan gzip ataupun brotli.

Selain kompresi di level transmisi, juga bisa diterapkan kompresi di level kode seperti melakukan minify agar kode yang dikirim hanya kode-kode yang penting saja.

1 whitespace (spasi/tab/break line) bisa memakan 1-2 byte, silahkan gunakan matematika untuk menghitung total bytes yang ada di kodemu khusus untuk whitespace saja.

Aset Media

Dokumen HTML adalah perpaduan antara teks dan aset media, perbandingannya bisa 50:50; 80:20, atau 40:60 tergantung website apa yang kamu buat/kunjungi.

Meskipun gambar tidak mem-block proses rendering (akan kita bahas nanti), tapi berpengaruh di load time. Meskipun gambar tidak mempengaruhi DOMContentLoaded time tapi berpengaruh ke load time.

DOMContentLoaded adalah kondisi ketika file HTML termuat & sudah di parse, tanpa perlu menunggu file css, gambar, dll selesai dimuat.

Sedangkan untuk load sendiri adalah kondisi ketika resources (yang tadi disebut diatas) dan subresources (in case ada iframe) sudah selesai dimuat. Jika sebelumnya favicon kamu ada indikator loading lalu hilang, berarti event load sudah terpanggil.

Hanya memberikan "gambar yang penting" saja sangat berpengaruh untuk mengurangi load time. Konteks "yang penting" tersebut biasanya mengarah ke gambar yang dilihat oleh pengguna di layar (based on their viewport).

Jadi, untuk gambar-gambar yang sekiranya gak terlihat (alias baru bisa dilihat ketika user melakukan scrolling), bisa diload "nanti" atau bahasa anak-anak frontend nya melakukan "lazy load".

Ya, kompresi untuk gambar pun sangat berpengaruh. Bisa menghemat beberapa bytes (bahkan kilo-mega bytes!).

Addy Osmani telah menulis "buku" tentang optimasi gambar yang bisa dibaca disini.

Untuk optimasi media lain selain gambar (video/audio), ini kembali ke cara kamu memuat media tersebut. Biasanya implementasinya di level aplikasi, dan menggunakan teknik chunking.

Jika file media tersebut berukuran total 30 MB, biasanya file tersebut akan dipecah (misal menjadi masing-masing 2MB), maka aplikasimu harus bisa meload sisa file dari yang sudah dipecah tersebut (total sekitar 15 file).

User-centric Performance metrics

Ada beberapa metriks yang bisa diukur untuk proses pemuatan suatu halaman, yakni:

  • First Paint (FP)
  • First Contentful Paint (FCP)
  • First Meaningful Paint (FMP)
  • DOMContentLoaded (DCL)
  • Largest Contentful Paint (LCP)
  • Load Event (OL)

Sebelumnya kita sudah membahas sedikit tentang DCL dan OL, sekarang mari kita bahas sedikit juga tentang FP, FCP, FMP, dan LCP.

First Paint & First Contentful Paint

Ini adalah tentang apa yang user lihat pertama kali dilayar.

Perbedaan antara FP dan FCP adalah bila FP tentang "tampilan berbeda" yang dilihat dari yang sebelumnya (misal dari blank screen menjadi enggak/ketika melakukan navigasi antar halaman).

Sedangkan FCP adalah tentang content pertama yang ditampilkan di layar (misal bila kamu memiliki element <p>ok</p>, bila dilayar user sudah melihat ok, maka sudah masuk ke bagian FCP.

Ini penting, untuk sedikit "mengelabui" user alias untuk membuat halaman tidak terasa lambat karena user sudah melihat sesuatu di layar.

First Meaningful Paint & Largest Contentful Paint

FMP & LCP memiliki perbedaan yang sangat... beda?

FMP adalah tentang "oke, gue liat tombol. apakah ini bisa di klik?"

LCP adalah tentang "oke ini gue udah bisa liat semua konten. persetan registering event listener, yang penting konten".

FMP & LCP penting juga, alasannya sama dengan yang sebelumnya.

Tergantung situs apa yang kamu buat/akses, jika situs seperti media tentu LCP sangat berperan penting. Jika aplikasi yang banyak interaksi, tentu kamu sudah tau jawabannya.

Sayangnya, FMP & LCP sistematis. Kita gak bisa menomor-satukan LCP lalu menomor-duakan FMP, karena LCP akan terjadi setelah FMP.

Metrics ini sebenernya gak penting-penting amat sih kalau lo gak peduli dengan psikologi user, apalagi kalau website lo kenceng nya gak ada obat soalnya cuma dokumen html gak ada file gambar, css dan js.

Tapi eksekutif menyukai metriks, alias, YA UKUR METRICS INI KALAU LO PUNYA USER.

Bundle Size

Ini yang paling berpengaruh dan merambat ke berbagai pembahasan.

Kalau website lo gak pakai CSS, JavaScript, dan gambar, ya tetep sih bundle size berperan penting.

Bundle size adalah tentang data yang harus diunduh oleh client (REMEMBER HOW FUCKING INTERNET WORKS???), jika ukuran halaman website lo 3MB dan kecepatan internet user adalah 1mbps, berarti perlu 3 detik untuk user mengunduh data tersebut.

Hanya mengunduh, tidak termasuk parsing; register event, execution, dsb.

Logikanya, semakin besar bundle size, semakin banyak yang harus client/browser lakuin. Entah itu mem-parsing sintaks HTML, mem-parsing kode JS dan sintaks CSS, melakukan register untuk event listener, melakukan rekues asingkronous, pokoknya semua deh.

Dan ini salah satu yang membuat loading website lo lambat, browser lo sibuk ngelakuin banyak mau lo khususnya di file JS lo.

Bundle size kecil, berarti kode yang di deliver juga kecil. Berarti, lebih sedikit yang browser lakuin juga. Jadi, YES SHIP SMALL CODE.

Di dokumen HTML, browser harus mem-parsing tag-tag yang ada menjadi DOM.

Di dokumen CSS, browser harus mem-parsing selector yang ada, dan menerapkannya ke DOM.

Di dokumen JS, browser harus mem-parsing syntax, ngelakuin apa yang harus dilakuin secara sistematis (based on your code), dan kemungkinan akan berpengaruh ke step dokumen HTML dan CSS diatas, dan repeat.

Browser akan melakukan proses dari Loading, Scripting, Rendering dan Painting. Dan ya, termasuk Re-loading, Re-scripting, Re-rendering, dan Re-painting.

3rd-party resources

Website kamu memuat gambar dari website random yang kamu temukan di Google Image? Atau, meng-embed iframe dari website apapun itu? Hmm memuat iklan dari raksasa penyedia jaringan iklan? Atau memuat script untuk keperluan tracking & tracing?

IYA SEMUANYA NGARUH.

Terlebih, kepentingan-kepentingan diatas tidak bisa di-kontrol (btw am I correctly writing it?) oleh kamu secara langsung.

Selain karena entah dimana mereka menyimpan servernya (hello round trip!), juga kamu mungkin tidak mengetahui "secara detail" tentang apa yang mereka lakukan (like, are they tracking every scrolling movement from user and how they do that).

Mengurangi sebanyak mungkin 3rd party resources akan membuat situs kita dimuat lebih cepat. You know, script iklan melakukan tracking, bukan? Biasanya, akan melakukan kalkulasi yang intinya untuk membuat kita unique dan bisa di identifikasi oleh mereka.

Dan lo kira gak ada biayanya untuk melakukan komputasi tadi?

Hanya menggunakan sumber daya yang penting aja dari pihak ketiga akan menambah kecepatan pemuatan website lo, so, JUST. DO. IT. YES YOU CAN.

Miscellaneous

Hal-hal lain yang tidak dibahas secara khusus disini antara lain:

  • CDN (Content Delivery Network)
  • Load Balancer
  • Service Worker
  • HTTP/2 (features) in depth
  • AMP (Google-level solution to fuck off your slow website)
  • WebP (another image format but in smaller™ size)
  • Advanced application-level optimization (this is your turn)
  • Advance JavaScript-level optimization
  • Suggest me somthing that not covered yet here

Kesimpulan

CEPETIN LOADING WEBSITE LO.

Penutup

Terima kasih sudah mampir, jangan lupa dengan kesimpulan diatas.

Menikmati tulisan ini?

Blog ini tidak menampilkan iklan, yang berarti blog ini didanai oleh pembaca seperti kamu. Gabung bersama yang telah membantu blog ini agar terus bisa mencakup tulisan yang lebih berkualitas dan bermanfaat!

Pendukung

Kamu?