Mari kita bicara sedikit tentang bagaimana mengamati berapa banyak sumber daya CPU yang dikonsumsi oleh kode JavaScript aplikasi. Pada saat yang sama, saya mengusulkan untuk membangun percakapan kami di sekitar komponen - blok bangunan dasar aplikasi. Dengan pendekatan ini, segala upaya untuk meningkatkan produktivitas (atau upaya untuk menemukan penyebab pelambatan program) dapat difokuskan pada (mudah-mudahan) fragmen kecil proyek yang mandiri. Pada saat yang sama, saya berasumsi bahwa aplikasi front-end Anda, seperti banyak proyek modern lainnya, dibuat dengan merakit fragmen kecil dari antarmuka yang cocok untuk penggunaan berulang. Jika tidak demikian, maka alasan kami dapat diterapkan ke aplikasi lain, tetapi Anda harus menemukan cara Anda sendiri untuk membagi kode skala besar Anda menjadi fragmen dan Anda perlu memikirkan cara menganalisis fragmen ini.

Mengapa ini dibutuhkan?
Mengapa mengukur konsumsi CPU dengan JavaScript? Faktanya adalah bahwa hari ini, kinerja aplikasi paling sering dikaitkan dengan kemampuan prosesor. Izinkan saya mengutip kata-kata Steve Soders dan Pat Minan dengan bebas dari wawancara yang saya ambil untuk
Planet Performance Podcast . Keduanya mengatakan bahwa kinerja aplikasi tidak lagi terbatas pada kemampuan jaringan atau latensi jaringan. Jaringan semakin cepat dan semakin cepat. Para pengembang, di samping itu, belajar untuk mengompres respons teks server menggunakan GZIP (atau, lebih tepatnya, menggunakan brotli) dan menemukan cara untuk mengoptimalkan gambar. Semuanya sangat sederhana.
Hambatan kinerja aplikasi modern adalah prosesor. Ini terutama berlaku di lingkungan seluler. Dan pada saat yang sama, harapan kami tentang kemampuan interaktif aplikasi web modern telah berkembang. Kami berharap antarmuka aplikasi tersebut akan bekerja dengan sangat cepat dan lancar. Dan semua ini membutuhkan lebih banyak kode JavaScript. Selain itu, kita harus ingat bahwa 1 MB gambar tidak sama dengan 1 MB JavaScript. Gambar diunduh secara progresif, dan aplikasi saat ini memecahkan masalah lain. Tetapi kode JavaScript sering berupa sumber daya seperti itu, yang tanpanya aplikasi menjadi tidak berfungsi. Untuk memastikan berfungsinya aplikasi modern, diperlukan sejumlah besar kode JS, yang, sebelum benar-benar berfungsi, harus diuraikan dan dijalankan. Dan ini adalah tugas yang sangat bergantung pada kemampuan prosesor.
Indikator kinerja
Kami akan menggunakan indikator kecepatan fragmen kode seperti jumlah instruksi prosesor yang diperlukan untuk memprosesnya. Ini akan memungkinkan kami untuk memisahkan pengukuran dari sifat-sifat komputer tertentu dan dari keadaan di mana ia berada pada saat pengukuran. Metrik berbasis waktu (seperti TTI) memiliki terlalu banyak "noise". Mereka tergantung pada keadaan koneksi jaringan, serta pada hal lain yang terjadi pada komputer pada saat pengukuran. Sebagai contoh, beberapa skrip yang dieksekusi saat memuat halaman yang diselidiki, atau virus yang sibuk dengan sesuatu di proses latar belakang, dapat mempengaruhi indikator kinerja temporal. Hal yang sama dapat dikatakan tentang ekstensi browser, yang dapat menghabiskan banyak sumber daya sistem dan memperlambat halaman. Ketika menghitung jumlah instruksi prosesor, di sisi lain, waktu tidak menjadi masalah. Indikator-indikator seperti itu, seperti yang akan segera Anda lihat, benar-benar stabil.
Ide
Inilah ide yang melatarbelakangi pekerjaan kami: kami perlu membuat "laboratorium" tempat kode akan diluncurkan dan diperiksa ketika ada perubahan. Yang saya maksud dengan "laboratorium" adalah komputer biasa, mungkin komputer yang sering Anda gunakan. Sistem kontrol versi memberi kami kait yang dapat digunakan untuk mencegat peristiwa tertentu dan melakukan pemeriksaan tertentu. Tentu saja, pengukuran di "laboratorium" dapat dilakukan setelah melakukan. Tetapi Anda mungkin tahu bahwa perubahan pada kode yang telah mencapai tahap komit akan dibuat lebih lambat dari pada kode yang sedang ditulis (jika ada). Hal yang sama berlaku untuk memperbaiki kode beta produk, dan memperbaiki kode yang masuk ke produksi.
Kami membutuhkan setiap kali kode diubah, kinerjanya dibandingkan sebelum dan setelah perubahan dibuat. Dalam melakukannya, kami berusaha untuk menyelidiki komponen secara terpisah. Sebagai hasilnya, kita akan dapat dengan jelas melihat masalah dan dapat mengetahui dengan tepat di mana mereka muncul.
Hal yang baik adalah bahwa studi seperti itu dapat dilakukan di browser nyata, menggunakan, misalnya, Dalang. Ini adalah alat yang memungkinkan Anda untuk mengontrol browser tanpa antarmuka pengguna dari Node.js.
Cari kode untuk penelitian
Untuk menemukan kode studi, kita dapat merujuk ke panduan gaya apa pun, atau ke sistem desain apa pun. Secara umum, kami senang dengan apa pun yang memberikan contoh singkat dan terisolasi dari penggunaan komponen.
Apa itu "panduan gaya"? Ini biasanya merupakan aplikasi web yang menunjukkan semua komponen atau "blok bangunan" elemen antarmuka pengguna yang tersedia untuk pengembang. Ini bisa berupa pustaka tertentu dari komponen pihak ketiga, atau sesuatu yang dibuat oleh upaya Anda sendiri.
Saat mencari proyek-proyek semacam itu di Internet, saya menemukan
utas diskusi baru-baru ini di Twitter yang berbicara tentang perpustakaan komponen React yang relatif baru. Saya melihat beberapa perpustakaan yang disebutkan di sana.
Tidak mengherankan, perpustakaan modern berkualitas tinggi disediakan dengan dokumentasi yang mencakup contoh kode kerja. Berikut adalah beberapa komponen perpustakaan dan
Button
diimplementasikan dengan cara mereka. Dokumentasi untuk perpustakaan ini berisi contoh penggunaan komponen ini. Kita berbicara tentang perpustakaan Chakra dan perpustakaan Semantic UI React.
Dokumentasi Komponen TombolTombol Semantic UI React DocumentationInilah yang kita butuhkan. Ini adalah contoh kode yang dapat kita periksa untuk konsumsi sumber daya prosesor mereka. Contoh serupa dapat ditemukan di isi dokumentasi, atau dalam kode komentar yang ditulis dengan gaya JSDoc. Mungkin, jika Anda beruntung, Anda akan menemukan contoh seperti itu, yang dirancang sebagai file terpisah, katakanlah, dalam bentuk file tes unit. Tentunya akan begitu. Bagaimanapun, kita semua menulis unit test. Benar?
File
Bayangkan, demi menunjukkan metode analisis kinerja yang dijelaskan, bahwa ada komponen
Button
di perpustakaan yang sedang kita pelajari, kode yang ada di file
Button.js
. File dengan unit test
Button-test.js
dilampirkan ke file ini, serta file dengan contoh penggunaan komponen -
Button-example.js
. Kita perlu membuat semacam halaman pengujian, di lingkungan di mana kode tes dapat dijalankan. Sesuatu seperti
test.html
.
Komponen
Berikut adalah komponen
Button
sederhana. Saya menggunakan Bereaksi di sini, tetapi komponen Anda dapat ditulis menggunakan teknologi apa pun yang nyaman untuk Anda.
import React from 'react'; const Button = (props) => props.href ? <a {...props} className="Button"/> : <button {...props} className="Button"/> export default Button;
Contoh
Dan ini adalah contoh penggunaan komponen
Button
. Seperti yang Anda lihat, dalam hal ini ada dua opsi komponen yang menggunakan properti berbeda.
import React from 'react'; import Button from 'Button'; export default [ <Button onClick={() => alert('ouch')}> Click me </Button>, <Button href="https://reactjs.com"> Follow me </Button>, ]
Tes
Berikut adalah halaman
test.html
yang dapat memuat komponen apa pun. Perhatikan pemanggilan metode ke objek
performance
. Dengan bantuan mereka, kami, atas permintaan kami, menulis ke file log kinerja Chrome. Kami akan segera menggunakan catatan ini.
const examples = await import(location.hash + '-example.js'); examples.forEach(example => performance.mark('my mark start'); ReactDOM.render(<div>{example}</div>, where); performance.mark('my mark end'); performance.measure( 'my mark', 'my mark start', 'my mark end'); );
Pelari ujian
Untuk memuat halaman pengujian di Chrome, kita dapat menggunakan perpustakaan
Puppeteer Node.js, yang memberi kita akses ke API untuk mengelola browser. Anda dapat menggunakan perpustakaan ini di sistem operasi apa pun. Ini memiliki salinan Chrome sendiri, tetapi juga dapat digunakan untuk bekerja dengan instance Chrome atau Chromium dari berbagai versi yang sudah ada di komputer pengembang. Chrome dapat diluncurkan sehingga jendelanya tidak terlihat. Pengujian dilakukan secara otomatis, sementara pengembang tidak perlu melihat jendela browser. Chrome dapat diluncurkan dalam mode normal. Ini berguna untuk keperluan debugging.
Berikut ini contoh skrip Node.js yang dijalankan dari baris perintah yang memuat halaman pengujian dan menulis data ke file log kinerja. Segala sesuatu yang terjadi di browser antara
tracing.start()
dan
end()
perintah ditulis (saya ingin mencatat, dengan sangat rinci) ke file
trace.json
.
import pup from 'puppeteer'; const browser = await pup.launch(); const page = await browser.newPage(); await page.tracing.start({path: 'trace.json'}); await page.goto('test.html#Button'); await page.tracing.stop(); await browser.close();
Pengembang dapat mengelola "detail" data kinerja dengan menentukan "kategori" penelusuran. Anda dapat melihat daftar kategori yang tersedia jika Anda membuka Chrome di
chrome://tracing
, klik
Record
dan buka bagian
Edit categories
di jendela yang muncul.
Mengkonfigurasi komposisi data yang ditulis ke log kinerjaHasil
Setelah halaman pengujian diperiksa menggunakan Puppeteer, Anda dapat menganalisis hasil pengukuran kinerja dengan membuka browser di
chrome://tracing
dan mengunduh file
trace.json
baru direkam.
Trace.json visualisasiDi sini Anda dapat melihat hasil memanggil metode
performance.measure('my mark')
. Panggilan
trace.json
measure()
hanya untuk keperluan debugging, jika pengembang ingin membuka file
trace.json
dan melihatnya. Segala sesuatu yang terjadi dengan halaman terlampir di blok
my mark
.
Berikut ini
trace.json
:
Fragmen file trace.jsonUntuk mengetahui apa yang kita butuhkan, cukup dengan mengurangkan indikator jumlah instruksi prosesor (
ticount
) dari
Start
marker dari indikator
End
marker yang sama. Ini memungkinkan Anda mengetahui berapa banyak instruksi prosesor yang diperlukan untuk menampilkan komponen di browser. Ini adalah nomor yang sama yang dapat Anda gunakan untuk mencari tahu apakah suatu komponen menjadi lebih cepat atau lebih lambat.
Iblis ada dalam perinciannya
Sekarang kami hanya mengukur indikator yang mengkarakterisasi output pertama ke halaman komponen tunggal. Dan tidak lebih. Sangat penting untuk mengukur indikator yang terkait dengan jumlah kode terkecil yang dapat dieksekusi. Ini memungkinkan Anda mengurangi tingkat "noise". Iblis ada dalam perinciannya. Semakin kecil kinerja yang diukur, semakin baik. Setelah pengukuran, perlu untuk menghapus dari hasil yang diperoleh apa yang di luar pengaruh pengembang. Misalnya, data yang terkait dengan operasi pengumpulan sampah. Komponen tidak mengontrol operasi seperti itu. Jika dijalankan, ini berarti bahwa browser, dalam proses rendering komponen, memutuskan untuk meluncurkannya sendiri. Akibatnya, sumber daya prosesor yang pergi ke pengumpulan sampah harus dihapus dari hasil akhir.
Blok data yang terkait dengan pengumpulan sampah ("blok data" ini lebih tepat disebut "peristiwa") disebut
V8.GCScavenger
.
tidelta
nya harus dikurangi dari jumlah instruksi prosesor yang masuk ke rendering komponen.
Berikut adalah dokumentasi untuk melacak peristiwa. Benar, ini sudah usang, dan tidak mengandung informasi tentang indikator yang kita butuhkan:
tidelta
- jumlah instruksi prosesor yang diperlukan untuk memproses suatu peristiwa.ticount
- jumlah instruksi untuk memulai acara.
Anda harus sangat berhati-hati tentang apa yang kami ukur. Browser adalah entitas yang sangat cerdas. Mereka mengoptimalkan kode yang berjalan lebih dari sekali. Pada grafik berikutnya, Anda dapat melihat jumlah instruksi prosesor yang diperlukan untuk menampilkan komponen tertentu. Operasi rendering pertama membutuhkan sumber daya terbanyak. Operasi selanjutnya membuat beban yang jauh lebih rendah pada prosesor. Ini harus diingat ketika menganalisis kinerja kode.
10 operasi rendering dari komponen yang samaBerikut ini detail lainnya: jika komponen melakukan beberapa operasi asinkron (misalnya, menggunakan
setTimeout()
atau
fetch()
), maka beban pada sistem yang dibuat oleh kode asinkron tidak diperhitungkan. Mungkin itu baik. Mungkin itu buruk. Jika Anda sedang menyelidiki kinerja komponen tersebut, pertimbangkan studi terpisah tentang kode asinkron.
Sinyal kuat
Jika Anda mengambil pendekatan yang bertanggung jawab untuk menyelesaikan masalah apa yang sebenarnya diukur, Anda bisa mendapatkan sinyal yang benar-benar stabil yang mencerminkan dampak pada kinerja setiap perubahan. Saya suka kelancaran garis-garis pada grafik berikutnya.
Hasil pengukuran yang stabilGrafik bawah menunjukkan hasil pengukuran 10 operasi rendering elemen
<span>
sederhana di Bereaksi. Tidak ada lagi yang termasuk dalam hasil ini. Ternyata operasi ini membutuhkan dari 2,15 hingga 2,2 juta instruksi prosesor. Jika Anda membungkus
<span>
dalam
<p>
, maka untuk menghasilkan desain seperti itu Anda membutuhkan sekitar 2,3 juta instruksi. Tingkat akurasi ini mengejutkan saya. Jika pengembang dapat melihat perbedaan kinerja yang muncul ketika satu elemen
<p>
ditambahkan ke halaman, ini berarti pengembang memiliki alat yang sangat kuat di tangan mereka.
Bagaimana tepatnya mewakili pengukuran keakuratan terserah pengembang. Jika dia tidak membutuhkan keakuratan seperti itu, dia selalu dapat mengukur kinerja rendering dari fragmen yang lebih besar.
Informasi kinerja tambahan
Sekarang pengembang memiliki sistem untuk menemukan indikator numerik yang sangat akurat mengkarakterisasi kinerja fragmen kode terkecil, pengembang dapat menggunakan sistem ini untuk menyelesaikan berbagai masalah. Jadi, menggunakan
performance.mark()
Anda dapat menulis informasi berguna tambahan untuk
trace.json
. Anda dapat memberi tahu anggota tim pengembangan apa yang terjadi dan apa yang menyebabkan peningkatan jumlah instruksi prosesor yang diperlukan untuk menjalankan beberapa kode. Anda dapat memasukkan informasi laporan kinerja tentang jumlah node DOM, atau tentang jumlah operasi penulisan dalam DOM yang dilakukan oleh React. Bahkan, di sini Anda dapat menampilkan informasi tentang banyak hal. Anda dapat menghitung jumlah perhitungan ulang tata letak halaman. Menggunakan Puppeteer Anda dapat mengambil tangkapan layar halaman dan membandingkan tampilan antarmuka sebelum dan sesudah membuat perubahan. Terkadang peningkatan jumlah instruksi prosesor yang diperlukan untuk menampilkan halaman terlihat benar-benar tidak mengejutkan. Misalnya, jika 10 tombol dan 12 bidang untuk mengedit dan memformat teks ditambahkan ke versi halaman yang baru.
Ringkasan
Apakah mungkin bagi semua orang yang dibahas di sini untuk menggunakannya hari ini? Ya kamu bisa. Untuk melakukan ini, Anda perlu Chrome versi 78 atau lebih tinggi. Jika
trace.json
memiliki
tidelta
dan
tidelta
, maka di atas tersedia untuk Anda. Versi sebelumnya dari Chrome tidak.
Sayangnya, informasi tentang jumlah instruksi prosesor tidak dapat diperoleh pada platform Mac. Saya belum mencoba Windows, jadi saya tidak bisa mengatakan apa-apa tentang OS ini. Secara umum - teman-teman kita adalah Unix dan Linux.
Perlu dicatat bahwa agar browser dapat memberikan informasi tentang instruksi prosesor, Anda perlu menggunakan beberapa flag - ini adalah
--no-sandbox
dan
--enable-thread-instruction-count
. Berikut ini cara meneruskannya ke browser yang diluncurkan oleh Puppeteer:
await puppeteer.launch({ args: [ '--no-sandbox', '--enable-thread-instruction-count', ]});
Semoga sekarang Anda dapat membawa analisis kinerja aplikasi web Anda ke tingkat selanjutnya.
Pembaca yang budiman! Apakah Anda berencana untuk menggunakan metodologi untuk menganalisis kinerja proyek web yang disajikan di sini?
