Pengukuran Kinerja Javascript

Mengukur waktu yang diperlukan untuk menjalankan suatu fungsi adalah cara yang baik untuk membuktikan bahwa satu implementasi mekanisme lebih produktif daripada yang lain. Ini memungkinkan Anda untuk memastikan bahwa kinerja fungsi tidak mengalami penurunan setelah beberapa perubahan pada kode. Ini juga membantu untuk mencari hambatan kinerja aplikasi.

Jika proyek web memiliki kinerja tinggi, ini berkontribusi terhadap persepsi positifnya oleh pengguna. Dan jika pengguna suka bekerja dengan sumber daya, mereka memiliki properti untuk kembali. Misalnya, dalam hal iniStudi ini menunjukkan bahwa 88% pelanggan online lebih kecil kemungkinannya untuk kembali ke sumber daya yang mereka temui dengan ketidaknyamanan apa pun. Ketidaknyamanan ini mungkin disebabkan oleh masalah kinerja.

Itulah sebabnya alat untuk membantu menemukan hambatan kinerja dan mengukur hasil peningkatan yang dilakukan terhadap kode penting dalam pengembangan web. Alat tersebut sangat relevan dalam pengembangan JavaScript. Sangat penting untuk mengetahui bahwa setiap baris kode JavaScript berpotensi memblokir DOM, karena JavaScript adalah bahasa berulir tunggal. Pada artikel ini saya akan berbicara tentang cara mengukur kinerja fungsi, dan apa yang harus dilakukan dengan hasil pengukuran.





Jika Anda berpikir bahwa beberapa perhitungan terlalu berat untuk dilakukan di utas utama, maka Anda mungkin memutuskan untuk memindahkannya ke pekerja layanan atau pekerja web.

Metode Performance.now ()


Antarmuka Kinerja memberikan akses ke nilai tipe DOMHighResTimeStamp melalui metode performance.now(). Metode ini mengembalikan stempel waktu yang menunjukkan waktu dalam milidetik yang telah berlalu sejak dokumen mulai ada. Selain itu, keakuratan indikator ini sekitar 5 mikrodetik (fraksi satu milidetik).

Untuk mengukur kinerja fragmen kode menggunakan metode ini performance.now(), Anda perlu melakukan dua pengukuran waktu, menyimpan hasil pengukuran ini dalam variabel, dan kemudian mengurangi hasil yang pertama dari hasil pengukuran kedua:

const t0 = performance.now();
for (let i = 0; i < array.length; i++) 
{
  // - 
}
const t1 = performance.now();
console.log(t1 - t0, 'milliseconds');

Di Chrome, setelah menjalankan kode ini, Anda bisa mendapatkan sesuatu seperti ini:

0.6350000001020817 "milliseconds"

Di Firefox, seperti ini:

1 milliseconds

Seperti yang Anda lihat, hasil pengukuran yang diperoleh di browser berbeda sangat berbeda. Faktanya adalah bahwa di Firefox 60, keakuratan hasil yang dikembalikan oleh API Kinerja berkurang. Kami akan berbicara lebih banyak tentang ini.

Antarmuka Kinerja memiliki kemampuan lebih dari sekadar mengembalikan stempel waktu tertentu. Ini termasuk mengukur berbagai aspek kinerja yang diwakili oleh ekstensi antarmuka ini seperti API Timeline Kinerja , Timing Navigasi , Timing Pengguna , Timing Sumber Daya . Berikut adalah bahan untuk mengetahui lebih lanjut tentang API ini.

Dalam kasus kami, kami berbicara tentang mengukur kinerja fungsi, jadi kami memiliki cukup peluang yang diberikan metode iniperformance.now().

Date.now () dan performance.now ()


Di sini Anda mungkin berpikir bahwa Anda dapat menggunakan metode ini untuk mengukur kinerja Date.now(). Ini memang mungkin, tetapi pendekatan ini memiliki kelemahan.

Metode Date.now()mengembalikan waktu dalam milidetik yang telah berlalu sejak era Unix (1970-01-01T00: 00: 00Z) dan tergantung pada jam sistem. Ini berarti tidak hanya bahwa metode ini tidak seakurat performance.now(), tetapi sebaliknya performance.now(), mengembalikan nilai yang, dalam kondisi tertentu, dapat didasarkan pada indikator clock yang salah. Inilah yang dikatakan Rich Gentlekor, seorang programmer yang terkait dengan mesin WebKit, β€œMungkin para programmer cenderung berpikir bahwa pembacaan kembali ketika mengaksesDateberdasarkan waktu sistem, sangat tidak mungkin untuk memanggil ideal untuk memonitor aplikasi nyata. Sebagian besar sistem memiliki daemon yang secara teratur menyinkronkan waktu. Menyesuaikan jam sistem selama beberapa milidetik setiap 15-20 menit adalah hal yang biasa. Dengan frekuensi seperti itu, pengaturan jam sekitar 1% dari pengukuran interval 10 detik akan menjadi tidak akurat. "

Metode Console.time ()


Pengukuran waktu menggunakan API ini sangat sederhana. Cukup, sebelum kode yang kinerjanya perlu Anda evaluasi, panggil metode tersebut console.time(), dan setelah kode ini - metode tersebut console.timeEnd(). Dalam hal ini, satu dan metode lain harus melewati argumen string yang sama. Pada satu halaman, hingga 10.000 timer seperti itu dapat digunakan secara bersamaan.

Keakuratan pengukuran waktu yang dibuat menggunakan API ini sama dengan ketika menggunakan API Kinerja, tetapi akurasi yang akan dicapai dalam setiap situasi tertentu tergantung pada browser.

console.time('test');
for (let i = 0; i < array.length; i++) {
  // - 
}
console.timeEnd('test');

Setelah mengeksekusi kode tersebut, sistem akan secara otomatis menampilkan informasi tentang waktu yang telah berlalu ke konsol.

Di Chrome, tampilannya akan seperti ini:

test: 0.766845703125ms

Di Firefox, seperti ini:

test: 2ms - timer ended

Sebenarnya, semua yang ada di sini sangat mirip dengan apa yang kami lihat saat bekerja dengannya performance.now().

Kekuatan metode console.time()ini adalah kemudahan penggunaannya. Yaitu, kita berbicara tentang fakta bahwa penerapannya tidak memerlukan deklarasi variabel tambahan dan menemukan perbedaan antara indikator yang dicatat di dalamnya.

Akurasi waktu berkurang


Jika Anda, menggunakan alat yang dijelaskan di atas, mengukur kinerja kode Anda di browser yang berbeda, maka Anda dapat memperhatikan fakta bahwa hasil pengukuran dapat bervariasi.

Alasannya adalah karena peramban berusaha melindungi pengguna dari serangan berbasis waktu dan dari mekanisme identifikasi peramban ( Sidik Jari Peramban ). Jika hasil pengukuran waktu ternyata terlalu akurat, ini dapat memberikan peluang bagi penyerang, misalnya, untuk mengidentifikasi pengguna.

Di Firefox 60, seperti yang telah disebutkan, keakuratan hasil pengukuran waktu berkurang . Ini dilakukan dengan menyetel nilai properti privacy.reduceTimerPrecisionke 2 ms.

Sesuatu yang perlu diingat ketika menguji kinerja


Sekarang Anda memiliki alat yang Anda inginkan untuk mengukur kinerja fungsi JavaScript. Tetapi sebelum Anda memulai bisnis, Anda perlu mempertimbangkan beberapa fitur yang akan kita bicarakan sekarang.

▍ Bagilah dan taklukkan


Misalkan, menyaring beberapa data, Anda memperhatikan pengoperasian aplikasi yang lambat. Tapi Anda tidak tahu persis di mana hambatan kinerja.

Daripada berspekulasi pada bagian mana dari kode yang berjalan lambat, akan lebih baik untuk mencari tahu menggunakan metode di atas.

Untuk melihat gambaran umum tentang apa yang terjadi, Anda harus terlebih dahulu menggunakan console.time()dan console.timeEnd()mengevaluasi kinerja blok kode, yang, mungkin, memiliki efek buruk pada kinerja. Maka Anda perlu melihat kecepatan masing-masing bagian dari blok ini. Jika salah satu dari mereka terlihat lebih lambat dari yang lain, Anda perlu memberikan perhatian khusus padanya dan bagaimana menganalisanya.

Semakin sedikit kode antara panggilan ke metode yang mengukur waktu, semakin rendah kemungkinan bahwa sesuatu yang tidak relevan dengan situasi masalah akan diukur.

▍ Mempertimbangkan fitur perilaku fungsi pada nilai input yang berbeda


Dalam aplikasi nyata, data yang diterima pada input fungsi tertentu bisa sangat berbeda. Jika Anda mengukur kinerja fungsi yang melewati kumpulan data yang dipilih secara acak, ini tidak akan memberikan informasi berharga yang dapat mengklarifikasi apa yang terjadi.

Fungsi ketika meneliti kinerja perlu dipanggil dengan data input yang menyerupai yang asli sebanyak mungkin.

▍ Jalankan fungsi berkali-kali


Misalkan Anda memiliki fungsi yang beralih pada array. Dia melakukan beberapa perhitungan menggunakan setiap elemen array, dan setelah itu mengembalikan array baru dengan hasil perhitungan. Berpikir untuk mengoptimalkan fungsi ini, Anda ingin tahu apa yang berfungsi lebih cepat dalam situasi Anda - satu putaran forEachatau satu putaran reguler for.

Berikut adalah dua opsi untuk fitur ini:

function testForEach(x) {
  console.time('test-forEach');
  const res = [];
  x.forEach((value, index) => {
    res.push(value / 1.2 * 0.1);
  });

  console.timeEnd('test-forEach')
  return res;
}

function testFor(x) {
  console.time('test-for');
  const res = [];
  for (let i = 0; i < x.length; i ++) {
    res.push(x[i] / 1.2 * 0.1);
  }

  console.timeEnd('test-for')
  return res;
}

Uji fungsi:

const x = new Array(100000).fill(Math.random());
testForEach(x);
testFor(x);

Setelah menjalankan kode, kami mendapatkan hasil berikut:

test-forEach: 27ms - timer ended
test-for: 3ms - timer ended

Siklus itu tampaknya forEachjauh lebih lambat daripada siklus itu for. Lagi pula, hasil tes menunjukkan dengan tepat ini?

Faktanya, setelah tes tunggal, masih terlalu dini untuk menarik kesimpulan seperti itu. Mari kita coba memanggil fungsi dua kali:

testForEach(x);
testForEach(x);
testFor(x);
testFor(x);

Kami mendapatkan yang berikut ini:

test-forEach: 13ms - timer ended
test-forEach: 2ms - timer ended
test-for: 1ms - timer ended
test-for: 3ms - timer ended

Ternyata fungsi yang digunakan forEach, disebut yang kedua kalinya, adalah secepat yang digunakan for. Tetapi, mengingat fakta bahwa forEachpanggilan fungsi pertama , fungsi bekerja jauh lebih lambat, mungkin masih tidak layak untuk digunakan.

▍ Uji kinerja di berbagai browser


Tes di atas dilakukan di Firefox. Tetapi bagaimana jika Anda menjalankannya di Chrome? Hasilnya akan sangat berbeda:

test-forEach: 6.156005859375ms
test-forEach: 8.01416015625ms
test-for: 4.371337890625ms
test-for: 4.31298828125ms

Faktanya adalah bahwa browser Chrome dan Firefox didasarkan pada mesin JavaScript yang berbeda yang menerapkan optimasi kinerja yang berbeda. Sangat berguna untuk mengetahui perbedaan-perbedaan ini.

Dalam hal ini, Firefox memiliki pengoptimalan yang lebih baik forEachdengan input yang serupa. Dan siklusnya forlebih cepat daripada forEachdi Chrome dan Firefox. Akibatnya, mungkin lebih baik memikirkan varian fungsi c for.

Ini adalah contoh yang baik, menunjukkan pentingnya mengukur kinerja di berbagai browser. Jika Anda mengevaluasi kinerja beberapa kode hanya di Chrome, Anda dapat sampai pada kesimpulan bahwa siklus forEach, dibandingkan dengan siklus for, tidak terlalu buruk.

▍ Menerapkan batasan buatan pada sumber daya sistem


Nilai yang diperoleh dalam percobaan kami tidak terlihat terlalu besar. Namun ketahuilah bahwa komputer yang digunakan untuk pengembangan biasanya jauh lebih cepat daripada, katakanlah, rata-rata telepon seluler tempat mereka menjelajahi web.

Untuk menempatkan diri Anda di tempat pengguna yang tidak memiliki perangkat tercepat, gunakan kemampuan browser untuk secara artifisial membatasi sumber daya sistem. Misalnya - untuk mengurangi kinerja prosesor.

Dengan pendekatan ini, 10 atau 50 milidetik dapat dengan mudah berubah menjadi 500.

▍ Mengukur kinerja relatif


Pengukuran kinerja biasanya tergantung tidak hanya pada perangkat keras, tetapi juga pada beban prosesor saat ini, dan pada beban kerja utas utama dari aplikasi JavaScript. Oleh karena itu, cobalah untuk mengandalkan indikator relatif yang mengkarakterisasi perubahan kinerja, karena indikator absolut yang diperoleh ketika menganalisis fragmen kode yang sama pada waktu yang berbeda dapat sangat bervariasi.

Ringkasan


Pada artikel ini, kami melihat beberapa API JavaScript yang dirancang untuk mengukur kinerja. Kami berbicara tentang cara menggunakannya untuk menganalisis kode nyata. Saya percaya bahwa untuk melakukan beberapa pengukuran sederhana, paling mudah digunakan console.time().

Saya merasa bahwa banyak pengembang front-end tidak cukup memperhatikan untuk mengukur kinerja proyek mereka. Dan mereka harus secara konstan memantau indikator yang relevan, karena produktivitas memengaruhi keberhasilan dan profitabilitas proyek.

Pembaca yang budiman! Jika Anda terus memantau kinerja proyek Anda, beri tahu kami bagaimana Anda melakukannya.


All Articles