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 menyortir data. JavaScript yang berjalan lama atau buruk adalah penyebab umum masalah performa. Anda harus berusaha sebisa mungkin meminimalkan dampaknya.

Pandu Lewis
Paul Lewis

JavaScript sering memicu perubahan visual. Terkadang hal tersebut langsung melalui manipulasi gaya, dan terkadang penghitungannya yang mengakibatkan perubahan visual, seperti menelusuri atau mengurutkan data. JavaScript yang berjalan lama atau buruk adalah penyebab umum masalah performa. Anda harus berusaha sebisa mungkin meminimalkan dampaknya.

Pembuatan profil performa JavaScript bisa jadi seni, karena JavaScript yang Anda tulis sama sekali dengan kode yang sebenarnya dieksekusi. Browser modern menggunakan compiler JIT serta segala cara pengoptimalan dan trik untuk mencoba dan memberi Anda eksekusi secepat mungkin, dan ini secara substansial mengubah dinamika kode.

Namun, dengan semua itu, ada beberapa hal yang pasti dapat Anda lakukan untuk membantu aplikasi mengeksekusi JavaScript dengan baik.

Ringkasan

  • Hindari 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 sejumlah 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 browser, yang tepat di awal frame. Satu-satunya cara untuk menjamin bahwa JavaScript akan berjalan di awal frame adalah dengan 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 pada titik tertentu dalam frame, mungkin tepat di akhir, dan sering kali dapat menyebabkan kita melewatkan frame, sehingga mengakibatkan jank.

setTimeout yang menyebabkan browser kehilangan bingkai.

Bahkan, jQuery sebelumnya menggunakan setTimeout untuk perilaku animate-nya. Aplikasi telah diubah untuk menggunakan requestAnimationFrame di versi 3. Jika menggunakan versi jQuery yang lebih lama, Anda dapat menambahnya untuk menggunakan requestAnimationFrame, yang sangat disarankan.

Kurangi kerumitan atau gunakan Web Workers

JavaScript berjalan di thread utama browser, tepat di samping penghitungan gaya, tata letak, dan, dalam banyak kasus, paint. Jika JavaScript Anda berjalan untuk waktu yang lama, JavaScript akan memblokir tugas lain ini, yang berpotensi menyebabkan frame terlewat.

Anda harus taktis tentang kapan JavaScript berjalan, dan untuk berapa lama. Misalnya, jika sedang dalam animasi seperti men-scroll, idealnya Anda harus mengatur JavaScript menjadi sesuatu di region 3-4 md. Jika lebih lama dari itu dan Anda berisiko memakan waktu terlalu banyak. Jika berada dalam periode tidak ada aktivitas, Anda dapat lebih santai dengan waktu yang dihabiskan.

Dalam banyak kasus, Anda dapat memindahkan tugas komputasi murni ke Pekerja Web, jika tidak memerlukan akses DOM, misalnya. Manipulasi atau traversal data, seperti pengurutan atau pencarian, sering kali cocok untuk model ini, seperti 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 dapat sesuai dengan model ini: Pekerja Web tidak memiliki akses DOM. Jika pekerjaan Anda harus berada di thread utama, pertimbangkan pendekatan pengelompokan, tempat Anda mengelompokkan 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 terhadap pendekatan ini, dan Anda harus memastikan bahwa pengguna mengetahui bahwa tugas sedang diproses, baik dengan menggunakan indikator progres atau indikator aktivitas. Dalam situasi apa pun, pendekatan ini akan membuat thread utama aplikasi tetap bebas, sehingga membantunya tetap responsif terhadap interaksi pengguna.

Ketahui "frame tax" JavaScript Anda

Saat menilai framework, library, atau kode Anda sendiri, penting untuk menilai biaya yang diperlukan untuk menjalankan kode JavaScript per frame. Hal ini sangat penting saat melakukan pekerjaan animasi yang penting bagi performa seperti transisi atau men-scroll.

Panel Performa di Chrome DevTools adalah cara terbaik untuk mengukur biaya JavaScript. Biasanya Anda mendapatkan catatan tingkat rendah seperti ini:

Rekaman performa di Chrome DevTools

Bagian Main menyediakan flame chart panggilan JavaScript sehingga Anda dapat menganalisis dengan tepat fungsi mana yang dipanggil dan durasi masing-masingnya.

Berbekal informasi ini, Anda dapat menilai dampak performa JavaScript pada aplikasi, dan mulai menemukan serta memperbaiki hotspot dengan fungsi yang memerlukan waktu terlalu lama untuk dijalankan. Seperti disebutkan di depan, Anda harus mencari untuk menghapus JavaScript yang berjalan lama, atau, jika tidak memungkinkan, memindahkannya ke Pekerja Web yang mengosongkan thread utama untuk melanjutkan tugas lain.

Lihat Mulai Menganalisis Performa Runtime untuk mempelajari cara menggunakan panel Performa.

Menghindari pengoptimalan mikro JavaScript Anda

Mungkin menyenangkan mengetahui bahwa browser dapat mengeksekusi satu versi sesuatu 100 kali lebih cepat daripada hal yang lain, misalnya meminta offsetTop elemen lebih cepat daripada menghitung getBoundingClientRect(), tetapi hampir selalu benar bahwa Anda hanya akan memanggil fungsi seperti ini beberapa kali per frame, jadi biasanya upaya untuk berfokus pada aspek performa JavaScript ini saja sia-sia. Anda biasanya hanya akan menghemat sepersekian milidetik.

Jika Anda membuat game, atau aplikasi yang mahal secara komputasi, maka Anda mungkin merupakan pengecualian dari panduan ini, karena Anda biasanya akan menyesuaikan banyak komputasi ke dalam satu frame, dan dalam hal ini semuanya akan membantu.

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