Meningkatkan performa Aplikasi HTML5

Pengantar

HTML5 memberi kita alat yang bagus untuk meningkatkan tampilan visual aplikasi web. Hal ini terutama berlaku di ranah animasi. Namun, dengan kemampuan baru ini juga muncul tantangan baru. Sebenarnya, tantangan ini tidak terlalu baru dan terkadang ada baiknya untuk bertanya kepada tetangga meja Anda yang ramah, programmer Flash, bagaimana ia mengatasi hal serupa di masa lalu.

Bagaimanapun, saat Anda mengerjakan animasi, sangat penting bagi pengguna untuk merasakan animasi ini berjalan lancar. Yang perlu kita sadari adalah bahwa kelancaran animasi tidak dapat benar-benar dibuat hanya dengan meningkatkan frame per detik di luar nilai minimum kognitif. Sayangnya, otak kita lebih cerdas dari itu. Yang akan Anda pelajari adalah bahwa 30 frame animasi per detik (fps) yang sebenarnya jauh lebih baik daripada 60 fps dengan hanya beberapa frame yang dihapus di tengah. Orang-orang tidak suka tepi yang tidak rata.

Artikel ini akan mencoba memberi Anda alat dan teknik untuk meningkatkan pengalaman aplikasi Anda sendiri.

Strategi

Kami tidak ingin membuat Anda ragu untuk membuat aplikasi visual yang luar biasa dengan HTML5.

Kemudian, jika Anda melihat bahwa performa bisa sedikit lebih baik, kembalilah ke sini dan baca cara meningkatkan elemen aplikasi Anda. Tentu saja, hal ini dapat membantu Anda melakukan beberapa hal dengan benar sejak awal, tetapi jangan biarkan hal itu menghalangi Anda untuk menjadi produktif.

Fidelitas visual++ dengan HTML5

Akselerasi Hardware

Akselerasi hardware adalah pencapaian penting untuk performa rendering secara keseluruhan di browser. Skema umumnya adalah memindahkan tugas yang akan dihitung oleh CPU utama ke unit pemrosesan grafis (GPU) di adaptor grafis komputer Anda. Hal ini dapat menghasilkan peningkatan performa yang besar dan juga dapat mengurangi konsumsi resource di perangkat seluler.

Aspek dokumen ini dapat dipercepat oleh GPU

  • Komposisi tata letak umum
  • Transisi CSS3
  • Transformasi 3D CSS3
  • Menggambar Kanvas
  • Gambar 3D WebGL

Meskipun akselerasi kanvas dan WebGL adalah fitur tujuan khusus yang mungkin tidak berlaku untuk aplikasi tertentu, tiga aspek pertama dapat membantu hampir semua aplikasi menjadi lebih cepat.

Apa yang dapat dipercepat?

Akselerasi GPU berfungsi dengan memindahkan tugas yang ditentukan dengan baik dan spesifik ke hardware khusus. Skema umumnya adalah dokumen Anda dibagi menjadi beberapa "lapisan" yang tidak berubah terhadap aspek halaman yang dipercepat. Lapisan ini dirender menggunakan pipeline render tradisional. GPU kemudian digunakan untuk menggabungkan lapisan ke satu halaman yang menerapkan "efek" yang dapat dipercepat dengan cepat. Kemungkinan hasilnya adalah objek yang dianimasikan di layar tidak memerlukan satu "penyeusunan ulang" halaman saat animasi terjadi.

Yang perlu Anda perhatikan adalah Anda perlu memudahkan mesin rendering untuk mengidentifikasi kapan mesin tersebut dapat menerapkan keajaiban akselerasi GPU-nya. Perhatikan contoh berikut:

Meskipun ini berfungsi, browser tidak benar-benar tahu bahwa Anda melakukan sesuatu yang seharusnya dianggap sebagai animasi yang lancar oleh manusia. Pertimbangkan apa yang terjadi jika Anda mencapai tampilan visual yang sama menggunakan transisi CSS3:

Cara browser menerapkan animasi ini sepenuhnya disembunyikan dari developer. Hal ini berarti browser dapat menerapkan trik seperti akselerasi GPU untuk mencapai sasaran yang ditentukan.

Ada dua flag command line yang berguna untuk Chrome guna membantu proses debug akselerasi GPU:

  1. --show-composited-layer-borders menampilkan batas merah di sekitar elemen yang dimanipulasi di tingkat GPU. Cocok untuk mengonfirmasi bahwa manipulasi Anda terjadi dalam lapisan GPU.
  2. --show-paint-rects semua perubahan non-GPU digambar dan ini akan menampilkan batas terang di sekitar semua area yang dicat ulang. Anda dapat melihat cara kerja browser yang mengoptimalkan area cat.

Safari memiliki flag runtime serupa yang dijelaskan di sini.

Transisi CSS3

Transisi CSS membuat animasi gaya menjadi mudah bagi semua orang, tetapi juga merupakan fitur performa yang cerdas. Karena transisi CSS dikelola oleh browser, fidelitas animasinya dapat ditingkatkan secara signifikan, dan dalam banyak kasus diakselerasi hardware. Saat ini, WebKit (Chrome, Safari, iOS) memiliki transformasi CSS yang dipercepat hardware, tetapi transformasi ini akan segera hadir di browser dan platform lainnya.

Anda dapat menggunakan peristiwa transitionEnd untuk membuat skrip ini menjadi kombinasi yang efektif, meskipun saat ini, merekam semua peristiwa akhir transisi yang didukung berarti memantau webkitTransitionEnd transitionend oTransitionEnd.

Banyak library kini telah memperkenalkan API animasi yang memanfaatkan transisi jika ada dan kembali ke animasi gaya DOM standar jika tidak. scripty2, transisi YUI, jQuery animate enhanced.

Terjemahan CSS3

Saya yakin Anda pernah menganimasikan posisi x/y elemen di seluruh halaman sebelumnya. Anda mungkin telah memanipulasi properti kiri dan atas gaya inline. Dengan transformasi 2D, kita dapat menggunakan fungsi translate() untuk mereplikasi perilaku ini.

Kita dapat menggabungkannya dengan animasi DOM untuk menggunakan hal terbaik

<div style="position:relative; height:120px;" class="hwaccel">

  <div style="padding:5px; width:100px; height:100px; background:papayaWhip;
              position:absolute;" id="box">
  </div>
</div>

<script>
document.querySelector('#box').addEventListener('click', moveIt, false);

function moveIt(evt) {
  var elem = evt.target;

  if (Modernizr.csstransforms && Modernizr.csstransitions) {
    // vendor prefixes omitted here for brevity
    elem.style.transition = 'all 3s ease-out';
    elem.style.transform = 'translateX(600px)';

  } else {
    // if an older browser, fall back to jQuery animate
    jQuery(elem).animate({ 'left': '600px'}, 3000);
  }
}
</script>

Kita menggunakan Modernizr untuk menampilkan pengujian Transformasi 2D CSS dan Transisi CSS. Jika demikian, kita akan menggunakan translate untuk mengubah posisi. Jika dianimasikan menggunakan transisi, ada kemungkinan besar browser dapat melakukan akselerasi hardware. Untuk mendorong browser ke arah yang benar, kita akan menggunakan "magic CSS bullet" dari atas.

Jika browser kita kurang mampu, kita akan kembali ke jQuery untuk memindahkan elemen. Anda dapat menggunakan plugin polyfill jQuery Transform oleh Louis-Remi Babe untuk membuat semuanya otomatis.

window.requestAnimationFrame

requestAnimationFrame diperkenalkan oleh Mozilla dan di-iterasi oleh WebKit dengan tujuan memberi Anda API native untuk menjalankan animasi, baik berbasis DOM/CSS maupun di <canvas> atau WebGL. Browser dapat mengoptimalkan animasi serentak menjadi satu siklus reflow dan repaint, sehingga menghasilkan animasi dengan fidelitas yang lebih tinggi. Misalnya, animasi berbasis JS yang disinkronkan dengan transisi CSS atau SVG SMIL. Selain itu, jika Anda menjalankan loop animasi di tab yang tidak terlihat, browser tidak akan terus menjalankannya, yang berarti lebih sedikit penggunaan CPU, GPU, dan memori, sehingga masa pakai baterai menjadi jauh lebih lama.

Untuk mengetahui detail selengkapnya tentang cara dan alasan menggunakan requestAnimationFrame, lihat artikel Paul Irish requestAnimationFrame untuk animasi cerdas.

Pembuatan profil

Jika Anda menemukan bahwa kecepatan aplikasi dapat ditingkatkan, saatnya untuk mempelajari pembuatan profil guna mengetahui tempat pengoptimalan dapat memberikan manfaat terbesar. Pengoptimalan sering kali akan berdampak negatif pada kemampuan pemeliharaan kode sumber Anda sehingga hanya boleh diterapkan jika diperlukan. Pembuatan profil memberi tahu Anda bagian kode mana yang akan memberikan manfaat terbesar jika performanya ditingkatkan.

Profiling JavaScript

Penganalisis profil JavaScript memberi Anda ringkasan tentang performa aplikasi Anda di tingkat fungsi JavaScript dengan mengukur waktu yang diperlukan untuk menjalankan setiap fungsi dari awal hingga akhir.

Waktu eksekusi kotor fungsi adalah keseluruhan waktu yang diperlukan untuk mengeksekusinya dari atas ke bawah. Waktu eksekusi bersih adalah waktu eksekusi kotor dikurangi waktu yang diperlukan untuk mengeksekusi fungsi yang dipanggil dari fungsi.

Beberapa fungsi lebih sering dipanggil daripada yang lain. Profiler biasanya memberi Anda waktu yang diperlukan untuk menjalankan semua pemanggilan serta waktu eksekusi rata-rata, minimum, dan maksimum.

Untuk mengetahui detail selengkapnya, lihat dokumentasi Chrome DevTools tentang pembuatan profil.

DOM

Performa JavaScript memiliki pengaruh yang kuat terhadap kelancaran dan responsivitas aplikasi Anda. Penting untuk memahami bahwa, meskipun profiler JavaScript mengukur waktu eksekusi JavaScript Anda, profiler tersebut juga secara tidak langsung mengukur waktu yang dihabiskan untuk melakukan operasi DOM. Operasi DOM ini sering kali menjadi inti masalah performa Anda.

function drawArray(array) {
  for(var i = 0; i < array.length; i++) {
    document.getElementById('test').innerHTML += array[i]; // No good :(
  }
}

Misalnya, dalam kode di atas, hampir tidak ada waktu yang dihabiskan untuk mengeksekusi JavaScript yang sebenarnya. Kemungkinan besar fungsi drawArray akan muncul di profil Anda karena berinteraksi dengan DOM dengan cara yang sangat boros.

Tips dan Trik

Fungsi Anonim

Fungsi anonim tidak mudah dibuat profilnya karena secara inheren tidak memiliki nama yang dapat ditampilkan di profiler. Ada dua cara untuk mengatasi masalah ini:

$('.stuff').each(function() { ... });

tulis ulang ke:

$('.stuff').each(function workOnStuff() { ... });

Tidak banyak yang tahu bahwa JavaScript mendukung penamaan ekspresi fungsi. Tindakan ini akan membuat keduanya muncul dengan sempurna di profiler. Ada satu masalah dengan solusi ini: Ekspresi bernama sebenarnya menempatkan nama fungsi ke dalam cakupan leksikonis saat ini. Hal ini dapat menimpa simbol lain, jadi berhati-hatilah.

Membuat profil fungsi panjang

Bayangkan Anda memiliki fungsi yang panjang dan Anda mencurigai bahwa sebagian kecil darinya mungkin menjadi penyebab masalah performa Anda. Ada dua cara untuk mengetahui bagian mana yang bermasalah:

  1. Metode yang benar: Faktorkan ulang kode Anda agar tidak menyertakan fungsi yang panjang.
  2. Metode menyelesaikan tugas yang tidak baik: tambahkan pernyataan dalam bentuk fungsi panggilan mandiri bernama ke kode Anda. Jika Anda sedikit berhati-hati, hal ini tidak akan mengubah semantik dan membuat bagian fungsi Anda muncul sebagai fungsi individual di profiler: js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... } Jangan lupa untuk menghapus fungsi tambahan ini setelah pembuatan profil selesai; atau bahkan menggunakannya sebagai titik awal untuk memfaktorkan ulang kode Anda.

Pembuatan Profil DOM

Alat pengembangan Chrome Web Inspector terbaru berisi "Tampilan Linimasa" baru yang menampilkan linimasa tindakan tingkat rendah yang dilakukan oleh browser. Anda dapat menggunakan informasi ini untuk mengoptimalkan operasi DOM. Anda harus berupaya mengurangi jumlah "tindakan" yang harus dilakukan browser saat kode Anda dieksekusi.

Tampilan linimasa dapat menghasilkan informasi dalam jumlah besar. Oleh karena itu, Anda harus mencoba membuat kasus pengujian minimal yang dapat dieksekusi secara independen.

Pembuatan Profil DOM

Gambar di atas menunjukkan output tampilan linimasa untuk skrip yang sangat sederhana. Panel kiri menampilkan operasi yang dilakukan oleh browser dalam urutan kronologis, sedangkan linimasa di panel kanan menampilkan waktu sebenarnya yang digunakan oleh setiap operasi.

Info selengkapnya tentang tampilan linimasa. Alat alternatif untuk pembuatan profil di Internet Explorer adalah DynaTrace Ajax Edition.

Strategi Pembuatan Profil

Memilih aspek

Saat Anda ingin membuat profil aplikasi, coba pilih aspek fungsinya yang mungkin memicu kelambatan sedekat mungkin. Kemudian, coba jalankan profil yang hanya mengeksekusi bagian kode yang relevan dengan aspek aplikasi ini. Hal ini akan membuat data pembuatan profil lebih mudah ditafsirkan karena tidak tercampur dengan jalur kode yang tidak terkait dengan masalah sebenarnya. Contoh yang baik untuk setiap aspek aplikasi Anda mungkin adalah:

  1. Waktu mulai (aktifkan profiler, muat ulang aplikasi, tunggu hingga inisialisasi selesai, hentikan profiler.
  2. Klik tombol dan animasi berikutnya (mulai profiler, klik tombol, tunggu hingga animasi selesai, hentikan profiler).
Pembuatan Profil GUI

Hanya menjalankan bagian yang tepat dari aplikasi Anda dapat lebih sulit dalam program GUI daripada saat Anda mengoptimalkan, misalnya, ray tracer dari mesin 3D Anda. Misalnya, jika Anda ingin membuat profil hal-hal yang terjadi saat mengklik tombol, Anda mungkin memicu peristiwa mouseover yang tidak terkait sehingga membuat hasil Anda kurang meyakinkan. Cobalah untuk menghindarinya :)

Antarmuka Terprogram

Ada juga antarmuka terprogram untuk mengaktifkan debugger. Hal ini memungkinkan kontrol yang akurat atas kapan pembuatan profil dimulai dan kapan berakhir.

Mulai pembuatan profil dengan:

console.profile()

Berhenti membuat profil dengan:

console.profileEnd()

Kemampuan diulang

Saat membuat profil, pastikan Anda benar-benar dapat mereproduksi hasil. Dengan demikian, Anda akan dapat mengetahui apakah pengoptimalan Anda benar-benar meningkatkan performa. Selain itu, pembuatan profil tingkat fungsi dilakukan dalam konteks seluruh komputer Anda. Ini bukanlah ilmu pasti. Setiap profil yang dijalankan mungkin dipengaruhi oleh banyak hal lain yang terjadi di komputer Anda:

  1. Timer yang tidak terkait di aplikasi Anda sendiri yang diaktifkan saat Anda mengukur hal lain.
  2. Pembersihan sampah memori melakukan tugasnya.
  3. Tab lain di browser Anda melakukan pekerjaan berat di thread operasi yang sama.
  4. Program lain di komputer Anda menggunakan CPU sehingga membuat aplikasi Anda lebih lambat.
  5. Perubahan tiba-tiba pada medan gravitasi bumi.

Sebaiknya jalankan jalur kode yang sama beberapa kali dalam satu sesi pembuatan profil. Dengan cara ini, Anda mengurangi pengaruh faktor di atas dan bagian yang lambat dapat terlihat lebih jelas.

Mengukur, meningkatkan, mengukur

Saat Anda mengidentifikasi titik lambat dalam program, coba pikirkan cara untuk meningkatkan perilaku eksekusi. Setelah Anda mengubah kode, profil lagi. Jika Anda puas dengan hasilnya, lanjutkan. Jika Anda tidak melihat peningkatan, sebaiknya Anda mengembalikan perubahan dan tidak membiarkannya "karena tidak ada salahnya".

Strategi Pengoptimalan

Meminimalkan interaksi DOM

Tema umum untuk meningkatkan kecepatan aplikasi klien web adalah meminimalkan interaksi DOM. Meskipun kecepatan mesin JavaScript telah meningkat dengan urutan magnitudo, akses ke DOM belum menjadi lebih cepat dengan kecepatan yang sama. Hal ini juga tidak akan pernah terjadi karena alasan yang sangat praktis (hal-hal seperti menata tata letak dan menggambar sesuatu di layar memerlukan waktu).

Menyimpan Node DOM dalam Cache

Setiap kali Anda mengambil node atau daftar node dari DOM, coba pikirkan apakah Anda dapat menggunakannya kembali dalam komputasi berikutnya (atau bahkan hanya iterasi loop berikutnya). Selama Anda tidak benar-benar menambahkan atau menghapus node di area yang relevan, hal ini sering terjadi.

Sebelum:

function getElements() {
  return $('.my-class');
}

Sesudah:

var cachedElements;
function getElements() {
  if (cachedElements) {
    return cachedElements;
  }
  cachedElements = $('.my-class');
  return cachedElements;
}

Nilai Atribut Cache

Dengan cara yang sama seperti menyimpan node DOM dalam cache, Anda juga dapat menyimpan nilai atribut dalam cache. Bayangkan Anda sedang menganimasikan atribut gaya node. Jika Anda tahu bahwa Anda (seperti di bagian kode tersebut) adalah satu-satunya yang akan menyentuh atribut tersebut, Anda dapat meng-cache nilai terakhir pada setiap iterasi sehingga Anda tidak perlu membacanya berulang kali.

Sebelum:

setInterval(function() {
  var ele = $('#element');
  var left = parseInt(ele.css('left'), 10);
  ele.css('left', (left + 5) + 'px');
}, 1000 / 30);

Setelah: js var ele = $('#element'); var left = parseInt(ele.css('left'), 10); setInterval(function() { left += 5; ele.css('left', left + 'px'); }, 1000 / 30);

Memindahkan Manipulasi DOM dari Loop

Loop sering kali menjadi hot spot untuk pengoptimalan. Coba pikirkan cara untuk memisahkan penghitungan angka yang sebenarnya dengan penggunaan DOM. Sering kali Anda dapat melakukan penghitungan, lalu setelah selesai, menerapkan semua hasilnya sekaligus.

Sebelum:

document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  document.getElementById('target').innerHTML += val;
}

Sesudah:

var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');

Menggambar Ulang dan Mengatur Ulang Aliran

Seperti yang telah dibahas sebelumnya, mengakses DOM relatif lambat. Proses ini menjadi sangat lambat saat kode Anda membaca nilai yang harus dihitung ulang karena kode Anda baru-baru ini mengubah sesuatu yang terkait di DOM. Oleh karena itu, sebaiknya hindari menggabungkan akses baca dan tulis ke DOM. Idealnya, kode Anda harus selalu dikelompokkan dalam dua fase:

  • Fase 1: Membaca nilai DOM yang diperlukan untuk kode Anda
  • Tahap 2: Ubah DOM

Cobalah untuk tidak memprogram pola seperti:

  • Tahap 1: Membaca nilai DOM
  • Tahap 2: Ubah DOM
  • Fase 3: Baca selengkapnya
  • Fase 4: Ubah DOM di tempat lain.

Sebelum:

function paintSlow() {
  var left1 = $('#thing1').css('left');
  $('#otherThing1').css('left', left);
  var left2 = $('#thing2').css('left');
  $('#otherThing2').css('left', left);
}

Sesudah:

function paintFast() {
  var left1 = $('#thing1').css('left');
  var left2 = $('#thing2').css('left');
  $('#otherThing1').css('left', left);
  $('#otherThing2').css('left', left);
}

Saran ini harus dipertimbangkan untuk tindakan yang terjadi dalam satu konteks eksekusi JavaScript. (misalnya, dalam pengendali peristiwa, dalam pengendali interval, atau saat menangani respons ajax.)

Menjalankan fungsi paintSlow() dari atas akan membuat gambar ini:

paintSlow()

Beralih ke implementasi yang lebih cepat akan menghasilkan gambar ini:

Implementasi yang lebih cepat

Gambar ini menunjukkan bahwa mengurutkan ulang cara kode Anda mengakses DOM dapat sangat meningkatkan performa rendering. Dalam hal ini, kode asli harus menghitung ulang gaya dan menata letak halaman dua kali untuk membuat hasil yang sama. Pengoptimalan serupa pada dasarnya dapat diterapkan ke semua kode "dunia nyata" dan menghasilkan beberapa hasil yang sangat dramatis.

Baca selengkapnya: Rendering: repaint, reflow/relayout, restyle oleh Stoyan Stefanov

Menggambar ulang dan Loop Peristiwa

Eksekusi JavaScript di browser mengikuti model "Event Loop". Secara default, browser berada dalam status "tidak ada aktivitas". Status ini dapat terganggu oleh peristiwa dari interaksi pengguna atau hal-hal seperti timer JavaScript atau callback Ajax. Setiap kali potongan JavaScript berjalan pada titik gangguan tersebut, browser biasanya akan menunggunya selesai hingga mewarnai ulang layar (Mungkin ada pengecualian untuk JavaScript yang berjalan sangat lama atau dalam kasus seperti kotak pemberitahuan yang secara efektif mengganggu eksekusi JavaScript).

Konsekuensi

  1. Jika siklus animasi JavaScript Anda memerlukan waktu lebih dari 1/30 detik untuk dieksekusi, Anda tidak akan dapat membuat animasi yang lancar karena browser tidak akan mewarnai ulang selama eksekusi JS. Jika Anda juga ingin menangani peristiwa pengguna, Anda harus melakukannya dengan lebih cepat.
  2. Terkadang, menunda beberapa tindakan JavaScript hingga nanti akan sangat berguna. Misalnya, setTimeout(function() { ... }, 0) Tindakan ini secara efektif memberi tahu browser untuk mengeksekusi callback segera setelah loop peristiwa tidak ada lagi aktivitas (secara efektif, beberapa browser akan menunggu setidaknya 10 md). Perlu diketahui bahwa hal ini akan membuat dua siklus eksekusi JavaScript yang sangat berdekatan waktunya. Keduanya dapat memicu pengecatan ulang layar yang dapat menggandakan keseluruhan waktu yang dihabiskan untuk proses pengecatan. Apakah hal ini benar-benar memicu dua gambar bergantung pada heuristik di browser.

Versi reguler:

function paintFast() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  $('#otherThing2').css('height', '20px');
}
Menggambar ulang dan Loop Peristiwa

Mari kita tambahkan beberapa penundaan:

function paintALittleLater() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  setTimeout(function() {
    $('#otherThing2').css('height', '20px');
  }, 10)
}
Keterlambatan

Versi yang tertunda menunjukkan bahwa browser menggambar dua kali meskipun dua perubahan pada halaman hanya 1/100 detik.

Inisialisasi Lambat

Pengguna menginginkan aplikasi web yang dimuat dengan cepat dan terasa responsif. Namun, pengguna memiliki nilai minimum yang berbeda untuk hal yang mereka anggap lambat, bergantung pada tindakan yang mereka lakukan. Misalnya, aplikasi tidak boleh melakukan banyak komputasi pada peristiwa mouseover karena hal ini dapat menciptakan pengalaman pengguna yang buruk saat pengguna terus menggerakkan mouse-nya. Namun, pengguna terbiasa menerima sedikit penundaan setelah mereka mengklik tombol.

Oleh karena itu, sebaiknya pindahkan kode inisialisasi Anda untuk dieksekusi selambat mungkin (misalnya, saat pengguna mengklik tombol yang mengaktifkan komponen tertentu dari aplikasi Anda).

Sebelum: js var things = $('.ele > .other * div.className'); $('#button').click(function() { things.show() });

Setelah: js $('#button').click(function() { $('.ele > .other * div.className').show() });

Delegasi Peristiwa

Menyebarkan pengendali peristiwa di seluruh halaman mungkin memerlukan waktu yang relatif lama dan juga bisa merepotkan setelah elemen diganti secara dinamis, yang kemudian memerlukan pemasangan ulang pengendali peristiwa ke elemen baru.

Solusinya dalam hal ini adalah menggunakan teknik yang disebut delegasi peristiwa. Alih-alih melampirkan setiap pengendali peristiwa ke elemen, sifat bubbling dari banyak peristiwa browser digunakan dengan benar-benar melampirkan pengendali peristiwa ke node induk dan memeriksa node target peristiwa untuk melihat apakah peristiwa tersebut menarik.

Di jQuery, hal ini dapat dengan mudah dinyatakan sebagai:

$('#parentNode').delegate('.button', 'click', function() { ... });

Kapan sebaiknya delegasi peristiwa tidak digunakan

Terkadang hal sebaliknya dapat terjadi: Anda menggunakan delegasi peristiwa dan mengalami masalah performa. Pada dasarnya, delegasi peristiwa memungkinkan waktu inisialisasi dengan kompleksitas konstan. Namun, harga untuk memeriksa apakah peristiwa menarik harus dibayar untuk setiap pemanggilan peristiwa tersebut. Hal ini mungkin akan mahal, terutama untuk peristiwa yang sering terjadi seperti "mouseover" atau bahkan "mousemove".

Masalah dan Solusi Umum

Hal yang saya lakukan di $(document).ready memerlukan waktu lama

Saran pribadi Malte: Jangan pernah melakukan apa pun di $(document).ready. Coba kirim dokumen Anda dalam bentuk final. Oke, Anda diizinkan untuk mendaftarkan pemroses peristiwa, tetapi hanya menggunakan pemilih ID dan/atau menggunakan delegasi peristiwa. Untuk peristiwa yang mahal seperti "mousemove", tunda pendaftaran hingga diperlukan (peristiwa mouseover pada elemen yang relevan).

Dan jika Anda benar-benar perlu melakukan sesuatu, seperti membuat permintaan Ajax untuk mendapatkan data sebenarnya, tampilkan animasi yang bagus; Anda mungkin ingin menyertakan animasi sebagai URI data jika animasi tersebut berupa GIF animasi atau sejenisnya.

Setelah saya menambahkan film Flash ke halaman, semuanya menjadi sangat lambat

Menambahkan Flash ke halaman akan selalu memperlambat rendering sedikit karena tata letak akhir jendela harus "dinegosiasikan" antara browser dan plugin Flash. Jika Anda tidak dapat sepenuhnya menghindari penempatan Flash di halaman, pastikan Anda menetapkan parameter Flash "wmode" ke nilai "window" (yang merupakan default). Tindakan ini akan menonaktifkan kemampuan untuk menggabungkan elemen HTML dan Flash (Anda tidak akan dapat melihat elemen HTML yang berada di atas film Flash dan film Flash Anda tidak dapat transparan). Hal ini mungkin merepotkan, tetapi akan meningkatkan performa Anda secara drastis. Misalnya, lihat cara youtube.com dengan hati-hati menghindari penempatan lapisan di atas pemutar film utama.

Saya menyimpan item ke localStorage, sekarang aplikasi saya tersendat

Menulis ke localStorage adalah operasi sinkron yang melibatkan pengaktifan hard disk Anda. Anda tidak boleh melakukan operasi sinkron "berjalan lama" saat melakukan animasi. Pindahkan akses ke localStorage ke tempat dalam kode Anda yang Anda yakin bahwa pengguna sedang tidak ada aktivitas dan tidak ada animasi yang sedang berlangsung.

Profil menunjukkan bahwa pemilih jQuery sangat lambat

Pertama, pastikan pemilih Anda dapat dijalankan melalui document.querySelectorAll. Anda dapat mengujinya di konsol JavaScript. Jika ada pengecualian, tulis ulang pemilih Anda agar tidak menggunakan ekstensi khusus framework JavaScript. Tindakan ini akan mempercepat pemilih Anda di browser modern dengan urutan magnitudo.

Jika cara ini tidak membantu atau jika Anda juga ingin cepat di browser modern, ikuti panduan berikut:

  • Jelaskan sespesifik mungkin di sisi kanan pemilih.
  • Gunakan nama tag yang jarang Anda gunakan sebagai bagian pemilih paling kanan.
  • Jika tidak ada yang membantu, pertimbangkan untuk menulis ulang agar Anda dapat menggunakan pemilih ID

Semua manipulasi DOM ini memerlukan waktu lama

Sejumlah penyisipan, penghapusan, dan pembaruan node DOM dapat berjalan sangat lambat. Hal ini umumnya dapat dioptimalkan dengan membuat string html yang besar dan menggunakan domNode.innerHTML = newHTML untuk mengganti konten lama. Perhatikan bahwa hal ini mungkin sangat buruk untuk pemeliharaan dan dapat membuat link memori di IE, jadi berhati-hatilah.

Masalah umum lainnya adalah kode inisialisasi Anda mungkin membuat banyak HTML. Misalnya, plugin jQuery yang mengubah kotak pilih menjadi sekumpulan div karena itulah yang diinginkan oleh desainer tanpa mengetahui praktik terbaik UX. Jika Anda benar-benar ingin halaman Anda cepat, jangan pernah melakukannya. Sebagai gantinya, kirimkan semua markup dari sisi server dalam bentuk akhirnya. Hal ini juga memiliki banyak masalah, jadi pikirkan dengan cermat apakah kecepatannya sebanding dengan pengorbanannya.

Alat

  1. JSPerf - Benchmark cuplikan kecil JavaScript
  2. Firebug - Untuk pembuatan profil di Firefox
  3. Alat Developer Google Chrome (Tersedia sebagai WebInspector di Safari)
  4. DOM Monster - Untuk mengoptimalkan performa DOM
  5. DynaTrace Ajax Edition - Untuk pembuatan profil dan pengoptimalan gambar di Internet Explorer

Bacaan lebih lanjut

  1. Google Speed
  2. Paul Irish tentang Performa jQuery
  3. Performa JavaScript Ekstrem (Slide Presentasi)