Mengoptimalkan eksekusi JavaScript

JavaScript sering memicu perubahan visual. Kadang-kadang itu secara langsung melalui manipulasi gaya, dan kadang-kadang penghitungannya yang menghasilkan perubahan visual, seperti mencari atau mengurutkan data. JavaScript yang berjalan lama atau jelek pengaturan waktunya adalah penyebab umum masalah kinerja. Anda harus berusaha meminimalkan dampaknya sebisa mungkin.

JavaScript sering memicu perubahan visual. Terkadang secara langsung melalui manipulasi gaya, dan terkadang hanya kalkulasi yang menghasilkan perubahan visual, seperti penelusuran atau pengurutan data. Waktunya buruk atau JavaScript yang berjalan lama adalah penyebab umum masalah kinerja. Anda harus berusaha meminimalkan dampaknya sebisa mungkin.

Pembuatan profil kinerja JavaScript mungkin suatu seni, karena JavaScript yang Anda tulis tidak seperti kode yang benar-benar dieksekusi. Browser modern menggunakan compiler JIT dan segala cara pengoptimalan dan trik untuk mencoba dan memberi Anda eksekusi secepat mungkin, dan ini secara substansial mengubah dinamika kode.

Namun, dengan demikian, ada beberapa hal yang pasti bisa Anda lakukan untuk membantu aplikasi Anda berjalan JavaScript dengan baik.

Ringkasan

  • Menghindari setTimeout atau setInterval untuk pembaruan visual; sebagai gantinya, selalu gunakan requestAnimationFrame.
  • Pindahkan JavaScript yang berjalan lama dari thread utama ke Web Worker.
  • Gunakan tugas mikro untuk membuat perubahan DOM melalui beberapa bingkai.
  • Gunakan Linimasa dan JavaScript Profiler di Chrome DevTools untuk menilai dampak JavaScript.

Menggunakan requestAnimationFrame untuk perubahan visual

Ketika perubahan visual terjadi di layar, Anda ingin melakukan pekerjaan pada waktu yang tepat untuk {i>browser<i} Anda, yang berada tepat di awal {i>frame<i}. Satu-satunya cara untuk memastikan bahwa JavaScript Anda akan berjalan di awal frame adalah menggunakan requestAnimationFrame.

/**
    * If run as a requestAnimationFrame callback, this
    * will be run at the start of the frame.
    */
function updateScreen(time) {
    // Make visual updates here.
}

requestAnimationFrame(updateScreen);

Framework atau contoh dapat menggunakan setTimeout atau setInterval untuk melakukan perubahan visual seperti animasi, tetapi masalahnya adalah callback akan berjalan di beberapa titik dalam frame, mungkin tepat di bagian akhir, dan sering kali dapat menyebabkan kita kehilangan frame, yang mengakibatkan jank.

setTimeout menyebabkan browser melewatkan frame.

Bahkan, jQuery sebelumnya menggunakan setTimeout untuk perilaku animate-nya. URL tersebut diubah menjadi menggunakan requestAnimationFrame dalam versi 3. Jika Anda menggunakan jQuery versi lama, Anda dapat menambalnya untuk menggunakan requestAnimationFrame, hal ini sangat disarankan.

Mengurangi kerumitan atau menggunakan Web Worker

JavaScript berjalan di utas utama browser, tepat di samping penghitungan gaya, tata letak, dan, di dalam banyak kasus, seperti cat. Jika JavaScript Anda berjalan untuk waktu yang lama, hal itu akan memblokir tugas-tugas lain, yang berpotensi menyebabkan {i> frame<i} terlewatkan.

Anda harus bersikap taktis terkait kapan JavaScript berjalan, dan untuk berapa lama. Misalnya, jika Anda berada di animasi seperti menggulir, idealnya Anda harus menjaga agar JavaScript Anda tetap area 3-4 md. Jika lebih lama dari itu, Anda berisiko menghabiskan terlalu banyak waktu. Jika Anda sedang tidak ada aktivitas waktu, Anda bisa lebih santai tentang waktu yang dibutuhkan.

Dalam banyak kasus, Anda dapat memindahkan pekerjaan komputasi murni ke Pekerja Web, jika, misalnya, tidak memerlukan akses DOM. Manipulasi data atau traversal, seperti pengurutan atau pencarian, sering kali cocok untuk model ini, seperti halnya pemuatan dan pembuatan model.

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener('message', function(evt) {
    var sortedData = evt.data;
    // Update data on screen...
});

Tidak semua pekerjaan cocok dengan model ini: Pekerja Web tidak memiliki akses DOM. Jika pekerjaan Anda harus berada di thread utama, pertimbangkan pendekatan pengelompokan, di mana Anda menyegmentasikan tugas yang lebih besar menjadi tugas mikro, masing-masing memerlukan waktu tidak lebih dari beberapa milidetik, dan berjalan di dalam pengendali requestAnimationFrame di setiap frame.

Ada konsekuensi UX dan UI dalam pendekatan ini, dan Anda perlu memastikan bahwa pengguna mengetahui bahwa tugas sedang diproses, baik dengan menggunakan indikator progres atau aktivitas. Bagaimanapun, pendekatan ini akan membuat thread utama aplikasi Anda tetap bebas, sehingga membantunya tetap responsif terhadap interaksi pengguna.

Ketahui “{i>frame tax<i}” JavaScript Anda

Saat menilai framework, library, atau kode Anda sendiri, sebaiknya berapa biaya yang diperlukan untuk menjalankan kode JavaScript pada basis {i>frame-by-frame<i}. Ini adalah sangat penting ketika melakukan pekerjaan animasi yang sangat penting seperti bertransisi atau menggulir.

Panel {i>Performance<i} di Chrome DevTools adalah cara terbaik untuk mengukur Biaya JavaScript. Biasanya Anda akan mendapatkan data tingkat rendah seperti ini:

Rekaman performa di Chrome DevTools

Bagian Utama menyediakan flame chart panggilan JavaScript sehingga Anda dapat menganalisis dengan tepat fungsi mana yang dipanggil dan berapa lama waktu yang dibutuhkan untuk setiap fungsi.

Berbekal informasi ini, Anda dapat menilai dampak performa JavaScript di aplikasi Anda, dan mulai menemukan dan memperbaiki hotspot di mana memakan waktu terlalu lama untuk dijalankan. Seperti yang disebutkan sebelumnya Anda harus mencari untuk menghapus JavaScript yang berjalan lama, atau, jika tidak memungkinkan, memindahkannya ke Pekerja Web membebaskan {i>thread <i}utama untuk melanjutkan tugas lain.

Lihat Mulai Menganalisis Performa Runtime untuk mempelajari cara menggunakan panel {i>Performance<i}.

Hindari pengoptimalan mikro JavaScript Anda

Mungkin keren mengetahui bahwa {i>browser<i} dapat menjalankan satu versi sesuatu 100 kali lebih cepat daripada hal lain, seperti meminta offsetTop elemen lebih cepat daripada menghitung getBoundingClientRect(), tetapi hampir selalu benar bahwa Anda hanya akan memanggil fungsi seperti beberapa kali per {i>frame<i}, jadi biasanya upaya yang sia-sia adalah untuk fokus pada aspek performa JavaScript. Biasanya Anda hanya akan menghemat sepersekian milidetik.

Jika Anda membuat game, atau aplikasi yang mahal secara komputasi, maka Anda mungkin sebuah pengecualian panduan ini, karena Anda biasanya akan memasukkan banyak komputasi ke dalam satu {i>frame<i}, dan jika demikian, semuanya akan membantu.

Singkatnya, Anda harus sangat berhati-hati terhadap pengoptimalan mikro karena biasanya tidak akan dipetakan ke jenis aplikasi yang Anda bangun.