Harga JavaScript 2019

Selama beberapa tahun terakhir, apa yang disebut " harga JavaScript " telah melihat perubahan positif besar karena peningkatan kecepatan parsing dan kompilasi skrip browser. Sekarang, pada 2019, komponen utama pemuatan pada sistem yang dibuat oleh JavaScript adalah waktu pemuatan skrip dan waktu pelaksanaannya.



Interaksi pengguna dengan situs mungkin sementara terganggu jika peramban sibuk mengeksekusi kode JavaScript. Sebagai hasilnya, kami dapat mengatakan bahwa optimalisasi kemacetan yang terkait dengan pemuatan dan pelaksanaan skrip dapat memiliki dampak positif yang kuat pada kinerja situs web.

Pedoman Praktis Umum untuk Optimasi Situs Web


Apa arti hal di atas bagi pengembang web? Intinya di sini adalah bahwa biaya sumber daya untuk parsing (parsing, parsing) dan kompilasi skrip tidak seserius sebelumnya. Karenanya, saat menganalisis dan mengoptimalkan bundel JavaScript, pengembang harus mempertimbangkan tiga rekomendasi berikut:

  1. Cobalah untuk mengurangi waktu yang diperlukan untuk mengunduh skrip.

    • Cobalah untuk menjaga bundel JS Anda kecil. Ini sangat penting untuk situs yang dirancang untuk perangkat seluler. Menggunakan bundel kecil meningkatkan waktu pemuatan kode, mengurangi tingkat penggunaan memori, dan mengurangi beban pada prosesor.
    • Cobalah untuk mencegah semua kode proyek dari disajikan sebagai satu bundel besar. Jika ukuran bundel melebihi sekitar 50-100 Kb - bagilah menjadi fragmen terpisah berukuran kecil. Berkat multiplexing HTTP / 2, beberapa permintaan server dan beberapa respons dapat diproses secara bersamaan. Ini mengurangi beban pada sistem yang terkait dengan kebutuhan untuk memenuhi permintaan tambahan untuk pemuatan data.
    • Jika Anda mengerjakan proyek seluler, usahakan agar kode sekecil mungkin. Rekomendasi ini dikaitkan dengan kecepatan data yang rendah melalui jaringan seluler. Selain itu, usahakan untuk penggunaan memori yang ekonomis.
  2. Cobalah untuk mengurangi waktu yang diperlukan untuk menjalankan skrip.

    • Hindari menggunakan tugas yang panjang yang dapat memuat utas utama untuk waktu yang lama dan menambah waktu yang dibutuhkan agar laman berada dalam kondisi di mana pengguna dapat berinteraksi dengannya. Di lingkungan saat ini, skrip yang dijalankan setelah dimuat memberikan kontribusi besar pada "harga JavaScript".
  3. Jangan menanamkan cuplikan kode besar di halaman.

    • Aturan berikut harus dipatuhi di sini: jika ukuran skrip melebihi 1 Kb, cobalah untuk tidak menanamkannya dalam kode halaman. Salah satu alasan untuk rekomendasi ini adalah kenyataan bahwa 1 Kb adalah batas setelah caching kode skrip eksternal mulai berfungsi di Chrome. Juga, perlu diingat bahwa parsing dan kompilasi skrip tertanam masih berjalan di utas utama.

Mengapa begitu penting untuk memuat dan menjalankan skrip?


Mengapa penting untuk mengoptimalkan waktu pemuatan dan eksekusi skrip dalam kondisi modern? Waktu pemuatan skrip sangat penting dalam situasi di mana situs diakses melalui jaringan lambat. Terlepas dari kenyataan bahwa jaringan 4G (dan bahkan 5G) semakin menyebar, properti NetworkInformation.effectiveType dalam banyak kasus menggunakan koneksi Internet seluler menunjukkan indikator yang berada pada level jaringan 3G atau bahkan pada level yang lebih rendah.

Waktu yang diperlukan untuk menjalankan kode JS penting untuk perangkat seluler dengan prosesor yang lambat. Karena kenyataan bahwa perangkat seluler menggunakan CPU dan GPU yang berbeda, karena fakta bahwa ketika perangkat terlalu panas, untuk melindunginya, kinerja komponen mereka menurun, Anda dapat mengamati kesenjangan serius antara kinerja ponsel dan tablet yang mahal dan murah. Ini sangat memengaruhi kinerja kode JavaScript, karena kemampuan untuk mengeksekusi kode tersebut oleh perangkat dibatasi oleh kemampuan prosesor perangkat ini.

Faktanya, jika kami menganalisis total waktu yang dihabiskan untuk memuat dan menyiapkan halaman untuk bekerja di browser seperti Chrome, sekitar 30% dari waktu ini dapat dihabiskan untuk mengeksekusi kode JS. Di bawah ini adalah analisis pemuatan halaman web yang sangat khas (reddit.com) pada komputer desktop berkinerja tinggi.


Dalam proses memuat halaman sekitar 10-30% dari waktu dihabiskan untuk eksekusi kode menggunakan V8

Jika kita berbicara tentang perangkat seluler, maka pada ponsel rata-rata (Moto G4) dibutuhkan 3-4 kali lebih lama untuk mengeksekusi reddit.com pada kode JS daripada pada perangkat tingkat tinggi (Pixel 3). Pada perangkat yang lemah (Alcatel 1X berharga kurang dari $ 100), menyelesaikan masalah yang sama membutuhkan waktu setidaknya 6 kali lebih banyak daripada sesuatu seperti Pixel 3.


Waktu yang diperlukan untuk memproses kode JS pada perangkat seluler dari berbagai kelas

Harap dicatat bahwa versi mobile dan desktop reddit.com berbeda. Karena itu, Anda tidak dapat membandingkan hasil perangkat seluler dan, katakanlah, MacBook Pro.

Saat Anda mencoba mengoptimalkan waktu eksekusi kode JavaScript, perhatikan tugas yang panjang yang dapat menangkap aliran UI untuk waktu yang lama. Tugas-tugas ini dapat menghambat pelaksanaan tugas-tugas lain yang sangat penting, bahkan ketika tampilan halaman tampak benar-benar siap untuk bekerja Tugas jangka panjang harus dipecah menjadi tugas yang lebih kecil. Dengan membagi kode menjadi bagian-bagian dan mengendalikan urutan pemuatan bagian-bagian ini, Anda dapat mencapai fakta bahwa halaman-halaman akan mencapai keadaan interaktif lebih cepat. Mudah-mudahan, ini akan menyebabkan pengguna memiliki sedikit ketidaknyamanan dalam berinteraksi dengan halaman.


Tugas jangka panjang menangkap utas utama. Mereka harus dipecah-pecah

Bagaimana peningkatan V8 mempercepat parsing dan kompilasi skrip?


Kecepatan penguraian kode JS sumber di V8, sejak zaman Chrome 60, telah meningkat 2 kali lipat. Pada saat yang sama, penguraian dan kompilasi sekarang berkontribusi lebih sedikit pada "harga JavaScript." Ini berkat upaya pengoptimalan Chrome lainnya yang mengarah ke paralelisasi tugas-tugas ini.

Di V8, jumlah pekerjaan pada parsing dan kode kompilasi yang dihasilkan di utas utama berkurang rata-rata 40%. Misalnya, untuk Facebook peningkatan indikator ini adalah 46%, untuk Pinterest - 62%. Hasil tertinggi, 81%, diperoleh untuk YouTube. Hasil tersebut dimungkinkan karena fakta bahwa parsing dan kompilasi dipindahkan ke aliran yang terpisah. Dan ini merupakan tambahan untuk perbaikan yang ada mengenai solusi streaming dari tugas yang sama di luar arus utama.


Waktu penguraian JS di berbagai versi Chrome

Anda juga dapat memvisualisasikan bagaimana pengoptimalan V8 yang dihasilkan dalam berbagai versi Chrome memengaruhi waktu prosesor yang diperlukan untuk memproses kode. Dalam waktu yang bersamaan dengan Chrome 61 yang diperlukan untuk menguraikan kode JS Facebook, Chrome 75 sekarang dapat menguraikan kode JS Facebook dan, di samping itu, menguraikan kode Twitter 6 kali.


Saat Chrome 61 diperlukan untuk memproses kode JS Facebook, Chrome 75 dapat memproses kode Facebook dan enam kali jumlah kode Twitter.

Mari kita bicara tentang bagaimana perbaikan tersebut dicapai. Singkatnya, sumber daya skrip dapat diuraikan dan dikompilasi dalam mode streaming dalam alur kerja. Ini berarti yang berikut:

  • V8 dapat mengurai dan mengkompilasi kode JS tanpa memblokir utas.
  • Pemrosesan aliran skrip dimulai ketika parser HTML universal menemukan <script> . Pengurai HTML menangani skrip yang memblokir penguraian halaman. Bertemu dengan skrip asinkron, ia terus bekerja.
  • Dalam sebagian besar skenario dunia nyata, yang ditandai oleh kecepatan koneksi jaringan tertentu, V8 mem-parsing kode lebih cepat daripada yang bisa dimuat. Akibatnya, V8 menyelesaikan tugas penguraian dan kompilasi kode beberapa milidetik setelah byte terakhir dari skrip dimuat.

Jika Anda membicarakan hal ini dengan sedikit lebih detail, maka intinya di sini adalah sebagai berikut. Di versi Chrome yang jauh lebih tua, skrip harus diunduh secara keseluruhan sebelum menguraikannya. Pendekatan ini sederhana dan dapat dimengerti, tetapi ketika digunakan, sumber daya prosesor digunakan secara tidak rasional. Chrome, antara versi 41 dan 68, mulai parsing dalam mode asinkron, segera setelah skrip mulai memuat, melakukan tugas ini di utas terpisah.


Skrip dikirim ke browser dalam fragmen. V8 mulai memproses streaming data setelah memiliki setidaknya 30 Kb kode.

Di Chrome 71, kami beralih ke sistem berbasis tugas. Di sini, penjadwal dapat secara bersamaan memulai beberapa sesi pemrosesan skrip asinkron / tertunda. Karena perubahan ini, beban yang dibuat oleh parsing utas utama telah berkurang sekitar 20%. Hal ini menyebabkan peningkatan sekitar 2% dalam skor TTI / FID yang diperoleh di situs nyata.


Chrome 71 menggunakan sistem pemrosesan kode berbasis tugas. Dengan pendekatan ini, penjadwal dapat memproses beberapa skrip asinkron / tertunda secara bersamaan.

Di Chrome 72, kami membuat streaming yang memproses cara utama untuk mem-parsing skrip. Sekarang bahkan skrip sinkron biasa ditangani dengan cara ini (meskipun ini tidak berlaku untuk skrip bawaan). Selain itu, kami berhenti membatalkan operasi parsing berbasis tugas jika utas utama membutuhkan kode yang diuraikan. Ini dilakukan karena fakta bahwa ini mengarah pada kebutuhan untuk melakukan kembali beberapa pekerjaan yang sudah dilakukan.

Versi Chrome sebelumnya memiliki dukungan untuk streaming parsing dan stream kompilasi kode. Kemudian skrip yang diunduh dari jaringan harus terlebih dahulu masuk ke aliran utama, dan kemudian akan dialihkan ke sistem pemrosesan skrip streaming.

Ini sering membuat parser aliran menunggu data yang sudah diunduh dari jaringan tetapi belum dialihkan oleh aliran utama ke pemrosesan aliran. Ini terjadi karena fakta bahwa utas utama bisa sibuk dengan beberapa tugas lain (seperti parsing HTML, membuat tata letak halaman atau menjalankan kode JS).

Sekarang kami sedang bereksperimen dengan cara memulai parsing kode saat membuka halaman sebelumnya. Sebelumnya, implementasi mekanisme seperti itu terhambat oleh kebutuhan untuk menggunakan sumber daya utas utama untuk mentransfer tugas ke parser streaming. Detail tentang penguraian kode JS yang menjalankan "secara instan" dapat ditemukan di sini .

Bagaimana pengaruhnya memengaruhi apa yang bisa dilihat di alat pengembang?


Selain hal di atas, dapat dicatat bahwa ada satu masalah pada alat pengembang sebelumnya. Itu terdiri dari fakta bahwa informasi tentang tugas parsing ditampilkan seolah-olah mereka benar-benar memblokir utas utama. Namun, parser melakukan operasi yang hanya memblokir utas utama saat diperlukan data baru. Karena kami pindah dari skema menggunakan aliran tunggal untuk memproses data streaming ke skema di mana tugas pemrosesan streaming diterapkan, ini menjadi sangat jelas. Inilah yang dapat Anda lihat di Chrome 69.


Masalahnya ada di alat pengembang, karena informasi tentang skrip parsing ditampilkan seolah-olah mereka benar-benar memblokir utas utama

Di sini Anda dapat melihat bahwa tugas Script Parse membutuhkan waktu 1,08 detik. Tetapi parsing JavaScript, pada kenyataannya, tidak begitu lambat! Sebagian besar waktu ini, tidak ada yang berguna dilakukan kecuali menunggu data dari utas utama.
Di Chrome 76, Anda sudah dapat melihat gambar yang sama sekali berbeda.


Di Chrome 76, penguraian dipecah menjadi banyak tugas kecil

Secara umum, dapat dicatat bahwa tab Performance dari alat pengembang sangat bagus untuk melihat gambaran keseluruhan dari apa yang terjadi pada halaman. Untuk mendapatkan informasi lebih rinci yang mencerminkan fitur-fitur V8, seperti waktu penguraian dan waktu kompilasi, Anda dapat menggunakan Chrome Tracing dengan dukungan RCS (Runtime Call Stats). Dalam data RCS yang diterima, Anda dapat menemukan indikator Parse-Background dan Compile-Background. Mereka dapat melaporkan berapa banyak waktu yang diperlukan untuk mem-parsing dan mengkompilasi kode JS di luar utas utama. Metrik Parse dan Kompilasi menunjukkan jumlah waktu yang dihabiskan untuk kegiatan terkait di utas utama.


Analisis data RCS menggunakan Google Tracing

Bagaimana perubahan memengaruhi pekerjaan dengan situs nyata?


Mari kita lihat beberapa contoh bagaimana pemrosesan skrip streaming memengaruhi penjelajahan situs nyata.

EddReddit



Lihat reddit.com di MacBook Pro. Waktu untuk parsing dan kompilasi kode JS dihabiskan di utas utama dan di utas pekerja

Ada beberapa bundel JS di situs web reddit.com, yang masing-masing melebihi ukuran 100 Kb. Mereka dibungkus dengan fungsi eksternal, yang mengarah ke pelaksanaan volume besar "malas" kompilasi di utas utama. Penting dalam diagram di atas adalah waktu yang diperlukan untuk memproses skrip di utas utama. Hal ini disebabkan oleh fakta bahwa beban yang besar pada utas utama dapat meningkatkan waktu yang dibutuhkan halaman untuk beralih ke mode interaktif. Saat memproses kode situs reddit.com, sebagian besar waktu dihabiskan di utas utama, dan sumber daya utas kerja / latar belakang digunakan seminimal mungkin.

Anda dapat mengoptimalkan situs ini dengan membagi beberapa bundel besar menjadi beberapa bagian (masing-masing sekitar 50 Kb) dan melakukan tanpa membungkus kode dalam suatu fungsi. Ini akan memaksimalkan pemrosesan paralel skrip. Akibatnya, bundel dapat diuraikan dan dikompilasi pada saat yang sama dalam mode streaming. Ini akan mengurangi beban pada utas utama saat menyiapkan halaman untuk pekerjaan.

โ–Facebook



Lihat facebook.com di MacBook Pro Anda. Waktu untuk parsing dan kompilasi kode JS dihabiskan di utas utama dan di utas pekerja

Kami juga dapat mempertimbangkan situs seperti facebook.com, yang menggunakan sekitar 6 MB kode JS terkompresi. Kode ini dimuat menggunakan sekitar 292 permintaan. Beberapa di antaranya asinkron, beberapa ditujukan untuk preloading data, beberapa memiliki prioritas rendah. Sebagian besar skrip Facebook berukuran kecil dan fokusnya sempit. Ini dapat memiliki efek yang baik pada pemrosesan data paralel dengan latar belakang / alur kerja. Faktanya adalah bahwa banyak skrip kecil dapat diuraikan dan dikompilasi pada saat yang sama melalui pemrosesan skrip streaming.

Harap perhatikan bahwa situs Anda mungkin berbeda dari situs Facebook. Anda mungkin tidak memiliki aplikasi yang dibiarkan terbuka untuk waktu yang lama (seperti apa situs Facebook atau antarmuka Gmail), dan ketika bekerja dengannya, mengunduh skrip dengan volume serius dengan browser desktop dapat dibenarkan. Namun, meskipun demikian, kami dapat memberikan rekomendasi umum yang adil untuk proyek apa pun. Itu terletak pada fakta bahwa ada baiknya memecah kode aplikasi menjadi bundel sederhana, dan bahwa Anda perlu mengunduh bundel ini hanya ketika ada kebutuhan bagi mereka.

Meskipun sebagian besar pekerjaan pada parsing dan kompilasi kode JS dapat dilakukan menggunakan alat streaming di utas latar, beberapa operasi masih memerlukan utas utama. Ketika utas utama sibuk dengan sesuatu, halaman tidak dapat menanggapi interaksi pengguna. Oleh karena itu, disarankan untuk memperhatikan dampak pada situs UX yang dimiliki pemuatan dan pelaksanaan kode JS.

Ingatlah bahwa tidak semua mesin JavaScript dan browser sekarang mengalirkan skrip dan mengoptimalkan pemuatannya. Namun terlepas dari ini, kami berharap bahwa prinsip optimasi umum yang diuraikan di atas dapat meningkatkan pengalaman pengguna bekerja dengan situs yang dilihat di salah satu browser yang ada.

Harga parsing JSON


Parsing kode JSON bisa jauh lebih efisien daripada parsing kode JavaScript. Masalahnya, tata bahasa JSON jauh lebih sederhana daripada tata bahasa JavaScript. Pengetahuan ini dapat diterapkan untuk meningkatkan kecepatan persiapan untuk pekerjaan aplikasi web yang menggunakan objek konfigurasi besar (seperti repositori Redux), struktur yang menyerupai kode JSON. Akibatnya, ternyata bahwa alih-alih menyajikan data sebagai objek literal yang tertanam dalam kode, Anda dapat mewakili mereka sebagai string objek JSON dan menguraikan objek-objek ini saat runtime.

Pendekatan pertama, menggunakan objek JS, terlihat seperti ini:

 const data = { foo: 42, bar: 1337 }; //  

Pendekatan kedua, menggunakan string JSON, melibatkan penggunaan konstruksi tersebut:

 const data = JSON.parse('{"foo":42,"bar":1337}'); //  

Karena Anda hanya perlu menjalankan pemrosesan string JSON sekali, pendekatan yang menggunakan JSON.parse jauh lebih cepat daripada menggunakan literal objek JavaScript. Terutama - pada pemuatan halaman "dingin". Disarankan agar Anda menggunakan string JSON untuk mewakili objek yang mulai dari 10 Kb. Namun, seperti tip kinerja apa pun, tip ini seharusnya tidak diikuti tanpa pertimbangan. Sebelum menerapkan teknik ini untuk menyajikan data dalam produksi, perlu untuk melakukan pengukuran dan mengevaluasi dampak nyata pada proyek.

Menggunakan objek literal sebagai penyimpanan untuk sejumlah besar data menimbulkan ancaman lain. Intinya adalah bahwa ada risiko literal tersebut dapat diproses dua kali:

  1. Pass pemrosesan pertama dilakukan dengan parsing awal dari literal.
  2. Pendekatan kedua dilakukan selama parsing "lazy" dari literal.

Anda tidak dapat menyingkirkan pass pertama dari pemrosesan literal objek. Namun, untungnya, pass kedua dapat dihindari dengan menempatkan objek literal di tingkat atas atau di dalam PIFE .

Bagaimana dengan parsing dan kompilasi kode pada kunjungan berulang ke situs?


Dimungkinkan untuk mengoptimalkan kinerja situs untuk kasus-kasus ketika pengguna mengunjunginya lebih dari sekali, berkat kemampuan V8 untuk kode caching dan bytecode. Saat skrip diminta dari server untuk pertama kalinya, Chrome mengunduh dan melewati V8 untuk kompilasi. Browser, selain itu, menyimpan file skrip ini dalam cache disk-nya. Ketika permintaan kedua untuk mengunduh file JS yang sama dijalankan, Chrome mengambilnya dari cache browser dan kembali melewati V8 untuk kompilasi. Namun kali ini, kode yang dikompilasi diserialisasi dan dilampirkan ke file skrip cache sebagai metadata.


Sistem caching kode di V8

Saat skrip diminta untuk ketiga kalinya, Chrome mengambil file dan metadata-nya dari cache, dan kemudian mentransfer V8 keduanya. V8 menghilangkan desimal metadata dan, sebagai akibatnya, dapat melewati langkah kompilasi. Caching kode dipicu jika kunjungan ke situs dilakukan dalam 72 jam. Chrome juga menggunakan strategi caching kode serakah ketika pekerja layanan digunakan untuk me-cache skrip. Detail tentang caching kode dapat ditemukan di sini .

Ringkasan


Pada 2019, hambatan kinerja utama untuk halaman web adalah memuat dan menjalankan skrip. Untuk memperbaiki situasi, berusaha untuk menggunakan skrip sinkron (built-in) berukuran kecil, yang diperlukan untuk mengatur interaksi pengguna dengan bagian halaman yang dapat dilihat langsung setelah memuat. Skrip yang digunakan untuk melayani bagian lain dari halaman disarankan untuk dimuat dalam mode ditangguhkan. Memecah bundel besar menjadi potongan-potongan kecil. Ini akan memfasilitasi implementasi strategi untuk bekerja dengan kode, dalam aplikasi kode dimuat hanya ketika dibutuhkan, dan hanya di mana diperlukan. Ini akan memaksimalkan kemampuan V8, yang ditujukan untuk pemrosesan kode secara paralel.

Jika Anda sedang mengembangkan proyek seluler, maka Anda harus berusaha untuk memastikan bahwa mereka menggunakan kode JS sesedikit mungkin. Rekomendasi ini berasal dari kenyataan bahwa perangkat seluler biasanya bekerja di jaringan yang cukup lambat. Perangkat seperti itu, di samping itu, mungkin terbatas dalam hal RAM yang tersedia dan sumber daya prosesor yang tersedia. Cobalah untuk menemukan keseimbangan antara waktu yang diperlukan untuk menyiapkan skrip yang diunduh dari jaringan dan menggunakan cache. Ini akan memaksimalkan jumlah penguraian dan kompilasi kode yang dilakukan di luar utas utama.

Pembaca yang budiman! Apakah Anda mengoptimalkan proyek web Anda dengan mempertimbangkan kekhasan pemrosesan kode JS oleh browser modern?

Source: https://habr.com/ru/post/id459296/


All Articles