Memuat resource JavaScript yang besar akan memengaruhi kecepatan halaman secara signifikan. Membagi JavaScript Anda menjadi potongan-potongan yang lebih kecil dan hanya mengunduh apa yang diperlukan untuk agar halaman berfungsi selama startup dapat meningkatkan pemuatan halaman secara signifikan responsivitas, sehingga dapat meningkatkan Interaksi ke Berikutnya di halaman Anda Paint (INP).
Saat laman mengunduh, mengurai, dan mengompilasi file JavaScript berukuran besar, hal itu bisa menjadi tidak responsif selama periode waktu tertentu. Elemen halaman terlihat, karena merupakan bagian dari HTML awal halaman dan diberi gaya oleh CSS. Namun, karena JavaScript yang diperlukan untuk menjalankan elemen-elemen interaktif tersebut—serta skrip lain yang dimuat halaman—mungkin mengurai dan mengeksekusi JavaScript agar mereka dapat berfungsi. Tujuan hasilnya adalah bahwa pengguna mungkin merasa seolah-olah interaksi itu signifikan tertunda, atau bahkan rusak sama sekali.
Hal ini sering terjadi karena thread utama diblokir, ketika JavaScript diuraikan dan dikompilasi di thread utama. Jika proses ini memakan waktu terlalu lama, elemen halaman mungkin tidak cukup cepat merespons input pengguna. Satu solusi untuk hal ini adalah dengan memuat hanya JavaScript yang Anda butuhkan agar halaman berfungsi, sementara menangguhkan JavaScript lain untuk dimuat nanti melalui teknik yang dikenal sebagai pemisahan. Modul ini berfokus pada cara yang terakhir dari kedua teknik tersebut.
Mengurangi penguraian dan eksekusi JavaScript selama startup melalui pemisahan kode
Lighthouse menampilkan peringatan jika eksekusi JavaScript membutuhkan waktu lebih dari 2 detik, dan gagal jika memerlukan waktu lebih dari 3,5 detik. JavaScript yang Berlebihan penguraian dan eksekusi berpotensi menjadi masalah mana saja di halaman siklus proses, karena berpotensi meningkatkan penundaan input interaksi jika waktu saat pengguna berinteraksi dengan halaman bertepatan dengan tugas thread utama yang bertanggung jawab untuk memproses dan mengeksekusi JavaScript sedang berjalan.
Lebih dari itu, eksekusi dan penguraian JavaScript yang berlebihan sangat bermasalah saat pemuatan awal halaman, karena ini adalah titik di halaman siklus proses di mana pengguna cenderung berinteraksi dengan halaman tersebut. Bahkan, Total Blocking Time (TBT)—metrik responsivitas pemuatan—berkorelasi yang sangat tinggi dengan INP, yang menunjukkan bahwa pengguna memiliki kecenderungan tinggi untuk mencoba interaksi selama pemuatan halaman awal.
Audit Lighthouse yang melaporkan waktu yang dihabiskan untuk menjalankan setiap file JavaScript permintaan halaman Anda berguna karena dapat membantu Anda mengidentifikasi dengan tepat skrip mungkin menjadi kandidat untuk pemisahan kode. Anda kemudian dapat melangkah lebih jauh dengan menggunakan alat cakupan di Chrome DevTools untuk mengidentifikasi secara tepat bagian mana dari {i>JavaScript <i}halaman tidak akan digunakan selama pemuatan halaman.
Pemisahan kode adalah teknik bermanfaat yang dapat mengurangi JavaScript awal halaman payload. Ini memungkinkan Anda membagi paket JavaScript menjadi dua bagian:
- JavaScript yang diperlukan saat halaman dimuat, sehingga tidak dapat dimuat di baik.
- Sisa JavaScript yang dapat dimuat di lain waktu, paling sering pada titik di mana pengguna berinteraksi dengan elemen interaktif yang diberikan di pada halaman.
Pemisahan kode dapat dilakukan menggunakan sintaksis import()
dinamis. Ini
sintaksis—tidak seperti elemen <script>
yang meminta resource JavaScript tertentu
saat startup—membuat permintaan untuk resource JavaScript di lain waktu selama
siklus proses halaman.
document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
// Get the form validation named export from the module through destructuring:
const { validateForm } = await import('/validate-form.mjs');
// Validate the form:
validateForm();
}, { once: true });
Dalam cuplikan JavaScript sebelumnya, modul validate-form.mjs
didownload, diuraikan, dan dieksekusi hanya saat pengguna memburamkan salah satu formulir
Kolom <input>
. Dalam situasi ini, sumber daya JavaScript yang bertanggung jawab untuk
mengarahkan logika validasi formulir hanya akan melibatkan halaman ketika
yang paling mungkin digunakan.
Pemaket JavaScript seperti webpack, Parcel, Rollup, dan esbuild dapat
dikonfigurasi untuk membagi paket JavaScript
menjadi potongan-potongan yang lebih kecil setiap kali
temukan panggilan import()
dinamis dalam kode sumber Anda. Sebagian besar {i>tool<i} ini melakukan
ini secara otomatis, tetapi esbuild secara khusus mengharuskan Anda untuk ikut serta
pengoptimalan.
Catatan bermanfaat tentang pemisahan kode
Meskipun pemisahan kode adalah metode efektif untuk mengurangi pertentangan thread utama selama pemuatan laman awal, ada baiknya untuk mengingat beberapa hal jika Anda memutuskan untuk mengaudit kode sumber JavaScript Anda guna mendapatkan peluang pemisahan kode.
Gunakan pemaket jika Anda bisa
Sudah menjadi praktik umum bagi developer untuk menggunakan modul JavaScript selama proses pengembangan Anda. Ini adalah peningkatan pengalaman developer yang luar biasa yang meningkatkan keterbacaan dan pengelolaan kode. Namun, ada beberapa karakteristik performa yang kurang optimal yang dapat dihasilkan saat mengirimkan JavaScript modul ke production.
Yang paling penting, Anda harus menggunakan pemaket untuk memproses dan mengoptimalkan sumber daya , termasuk modul yang ingin Anda pisahkan kodenya. Bundler sangat efektif dalam tidak hanya menerapkan pengoptimalan ke kode sumber JavaScript, tetapi juga cukup efektif dalam menyeimbangkan pertimbangan performa seperti ukuran paket terhadap rasio kompresi. Efektivitas kompresi meningkat sesuai ukuran paket, tetapi pemaket juga mencoba memastikan bahwa paket tidak terlalu besar sehingga dikenakan tugas yang berjalan lama karena evaluasi skrip.
Pemaket juga menghindari masalah pengiriman modul yang tidak dipaketkan dalam jumlah besar
melalui jaringan. Arsitektur yang menggunakan modul JavaScript cenderung memiliki
struktur hierarki modul yang kompleks. Jika hierarki modul tidak dipaket, setiap modul merepresentasikan
permintaan HTTP terpisah, dan interaktivitas di aplikasi web Anda mungkin tertunda jika Anda
tidak memaketkan modul. Meskipun Anda dapat menggunakan
Petunjuk resource <link rel="modulepreload">
untuk memuat hierarki modul besar sedini
sebanyak mungkin, paket JavaScript masih lebih disukai daripada performa pemuatan
dari sudut pandang yang lebih luas.
Jangan menonaktifkan kompilasi streaming secara tidak sengaja
Mesin JavaScript V8 Chromium menawarkan sejumlah pengoptimalan yang siap pakai untuk memastikan kode JavaScript produksi Anda dimuat seefisien mungkin. Salah satu pengoptimalan ini dikenal sebagai kompilasi streaming yang—seperti penguraian bertahap HTML yang di-streaming ke browser—mengompilasi potongan kode yang di-streaming saat JavaScript tiba dari jaringan.
Anda memiliki beberapa cara untuk memastikan bahwa kompilasi streaming terjadi untuk aplikasi web di Chromium:
- Ubah kode produksi Anda untuk menghindari penggunaan modul JavaScript. Bundle dapat mengubah kode sumber JavaScript Anda berdasarkan target kompilasi, dan target sering kali bersifat spesifik untuk lingkungan tertentu. V8 akan menerapkan streaming kompilasi ke kode JavaScript apa pun yang tidak menggunakan modul, dan Anda bisa mengonfigurasi pemaket Anda untuk mengubah kode modul JavaScript menjadi sintaksis yang tidak menggunakan modul JavaScript dan fitur-fiturnya.
- Jika Anda ingin mengirimkan modul JavaScript ke produksi, gunakan
.mjs
ekstensi. Baik JavaScript produksi Anda menggunakan modul maupun tidak, ada tidak ada jenis konten khusus untuk JavaScript yang menggunakan modul versus JavaScript sementara yang tidak. Jika V8 khawatir, Anda secara efektif memilih untuk tidak ikut streaming kompilasi saat Anda mengirimkan modul JavaScript dalam lingkungan production menggunakan.js
. Jika Anda menggunakan ekstensi.mjs
untuk modul JavaScript, V8 dapat memastikan kompilasi streaming untuk kode JavaScript berbasis modul tidak rusak.
Jangan biarkan pertimbangan ini menghalangi Anda menggunakan pemisahan kode. Kode adalah cara efektif untuk mengurangi {i>payload<i} JavaScript awal kepada pengguna, tetapi dengan menggunakan bundler dan mengetahui cara mempertahankan streaming V8 perilaku kompilasi, Anda dapat memastikan bahwa kode JavaScript produksi Anda cepat bagi pengguna.
Demo impor dinamis
paket web
webpack dilengkapi dengan plugin bernama SplitChunksPlugin
, yang memungkinkan Anda
mengonfigurasi cara pemaket membagi file JavaScript. webpack mengenali
pernyataan import()
dinamis dan import
statis. Perilaku
SplitChunksPlugin
dapat diubah dengan menentukan opsi chunks
di
konfigurasi:
chunks: async
adalah nilai default dan merujuk pada panggilanimport()
dinamis.chunks: initial
merujuk ke panggilanimport
statis.chunks: all
mencakup imporimport()
dinamis dan statis, sehingga Anda dapat untuk berbagi potongan antara imporasync
daninitial
.
Secara default, setiap kali webpack menemukan pernyataan import()
dinamis. ini
membuat potongan terpisah
untuk modul tersebut:
/* main.js */
// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';
myFunction('Hello world!');
// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
// Assumes top-level await is available. More info:
// https://v8.dev/features/top-level-await
await import('/form-validation.js');
}
Konfigurasi webpack default untuk cuplikan kode sebelumnya menghasilkan dua potongan yang terpisah:
- Potongan
main.js
—yang diklasifikasikan webpack sebagai potonganinitial
—yang mencakup modulmain.js
dan./my-function.js
. - Potongan
async
, yang hanya mencakupform-validation.js
(berisi hash file dalam nama resource jika dikonfigurasi). Potongan ini hanya didownload jika dan saatcondition
benar.
Konfigurasi ini memungkinkan Anda menunda
pemuatan potongan form-validation.js
hingga
yang sebenarnya dibutuhkan. Hal ini dapat meningkatkan responsivitas pemuatan dengan mengurangi skrip
evaluasi selama pemuatan halaman awal. Download dan evaluasi skrip
untuk potongan form-validation.js
terjadi saat kondisi tertentu terpenuhi,
dalam hal ini, modul yang diimpor
secara dinamis akan diunduh. Salah satu contohnya adalah
kondisi di mana polyfill hanya diunduh untuk browser tertentu, atau—seperti pada
contoh sebelumnya—modul yang diimpor diperlukan untuk interaksi pengguna.
Di sisi lain, mengubah konfigurasi SplitChunksPlugin
untuk menentukan
chunks: initial
memastikan bahwa kode hanya dibagi pada potongan awal. Berikut adalah
potongan seperti yang diimpor secara statis, atau tercantum dalam entry
webpack
properti. Melihat contoh sebelumnya, potongan yang dihasilkan adalah
kombinasi form-validation.js
dan main.js
dalam satu file skrip,
yang mengakibatkan performa pemuatan halaman awal
yang lebih buruk.
Opsi untuk SplitChunksPlugin
juga dapat dikonfigurasi untuk memisahkan
skrip menjadi beberapa skrip yang lebih kecil—misalnya dengan menggunakan opsi maxSize
untuk menginstruksikan webpack agar membagi potongan menjadi file
terpisah jika potongan tersebut melebihi apa yang
ditentukan oleh maxSize
. Membagi file skrip besar menjadi file yang lebih kecil dapat
meningkatkan responsivitas beban, seperti dalam beberapa kasus, evaluasi skrip yang menggunakan CPU secara intensif
pekerjaan dibagi menjadi tugas-tugas yang lebih kecil, yang cenderung tidak menghambat
untuk jangka waktu yang lebih lama.
Selain itu, membuat file JavaScript yang lebih besar juga berarti bahwa skrip kemungkinan besar akan terjadi pembatalan validasi cache. Misalnya, jika Anda mengirimkan skrip besar dengan kerangka kerja dan kode aplikasi pihak pertama, seluruh paket dapat dibatalkan jika hanya framework yang diupdate, tetapi tidak ada lagi resource yang dipaketkan.
Di sisi lain, file skrip yang lebih kecil meningkatkan kemungkinan bahwa pengunjung mengambil sumber daya dari cache, sehingga pemuatan halaman menjadi lebih cepat kunjungan berulang. Namun, file yang lebih kecil mendapat manfaat yang lebih sedikit dari kompresi dibandingkan dengan file yang lebih besar satu, dan dapat meningkatkan waktu round-trip jaringan pada pemuatan halaman dengan dalam cache browser. Harus diperhatikan untuk mencapai keseimbangan antara penyimpanan dalam cache efisiensi, efektivitas kompresi, dan waktu evaluasi skrip.
demo webpack
demo SplitChunksPlugin
webpack.
Menguji pengetahuan Anda
Jenis pernyataan import
mana yang digunakan saat menjalankan kode
memisahkan?
import()
dinamis.import
statis.
Jenis pernyataan import
manakah yang harus berada di bagian atas
modul JavaScript, dan tidak ada di lokasi lain?
import()
dinamis.import
statis.
Saat menggunakan SplitChunksPlugin
di webpack, apa
perbedaan antara potongan async
dan
initial
potongan?
async
potongan dimuat menggunakan import()
dinamis
dan potongan initial
dimuat menggunakan
import
.
async
potongan dimuat menggunakan import
statis
dan potongan initial
dimuat menggunakan
import()
.
Berikutnya: Gambar pemuatan lambat dan elemen <iframe>
Meskipun ini cenderung menjadi jenis sumber daya yang cukup mahal, JavaScript bukanlah
satu-satunya jenis sumber daya yang
bisa Anda tunda pemuatannya. Gambar dan elemen <iframe>
berpotensi menimbulkan biaya mahal. Mirip dengan JavaScript, Anda dapat
dapat menunda pemuatan gambar dan elemen <iframe>
dengan pemuatan lambat
mereka, seperti yang dijelaskan di modul berikutnya dalam kursus ini.