Kemunculan AJAX telah banyak mengubah mode operasi klien aplikasi Web. Hal ini memungkinkan pengguna untuk berkonsentrasi pada pekerjaan mereka tanpa harus sering mengalami penyegaran halaman yang mengganggu. Secara teori, teknologi AJAX dapat mengurangi waktu tunggu operasi pengguna secara signifikan dan menghemat lalu lintas data di jaringan. Namun, hal ini tidak selalu terjadi. Pengguna sering mengeluh bahwa kecepatan respon sistem yang menggunakan AJAX berkurang.
Penulis telah terlibat dalam penelitian dan pengembangan AJAX selama bertahun-tahun dan berpartisipasi dalam pengembangan dorado, platform AJAX yang relatif matang di Tiongkok. Berdasarkan pengalaman penulis, penyebab utama dari hasil ini bukanlah AJAX. Seringkali penurunan kecepatan respons sistem disebabkan oleh desain antarmuka yang tidak masuk akal dan kebiasaan pemrograman yang kurang efisien. Di bawah ini kami akan menganalisis beberapa aspek yang perlu diperhatikan selama proses pengembangan AJAX.
Penggunaan pemrograman klien dan panggilan prosedur jarak jauh dengan benar.
Pemrograman sisi klien sebagian besar didasarkan pada JavaScript. JavaScript adalah bahasa pemrograman yang ditafsirkan, dan efisiensi pengoperasiannya sedikit lebih rendah dibandingkan Java. Pada saat yang sama, JavaScript berjalan di lingkungan yang sangat dibatasi seperti browser. Oleh karena itu pengembang harus memiliki pemahaman yang jelas tentang logika mana yang dapat dieksekusi di sisi klien.
Bagaimana pemrograman sisi klien harus digunakan dalam aplikasi sebenarnya bergantung pada pengalaman dan penilaian pengembang. Banyak masalah di sini yang hanya bisa dipahami. Karena terbatasnya ruang, di sini kami secara kasar merangkum tindakan pencegahan berikut:
Sebisa mungkin hindari penggunaan panggilan prosedur jarak jauh, misalnya, hindari penggunaan panggilan prosedur jarak jauh di badan loop.
Jika memungkinkan, gunakan panggilan prosedur jarak jauh AJAX (panggilan prosedur jarak jauh asinkron).
Hindari menempatkan operasi data kelas berat di sisi klien. Misalnya: operasi penyalinan data dalam jumlah besar, penghitungan yang memerlukan traversal data dalam jumlah besar, dll.
Meningkatkan metode operasi objek DOM.
Dalam pemrograman sisi klien, operasi pada objek DOM sering kali paling memakan waktu CPU. Untuk pengoperasian objek DOM, perbedaan performa antara metode pemrograman yang berbeda seringkali sangat besar.
Berikut ini adalah tiga buah kode dengan hasil yang sama persis. Fungsinya untuk membuat tabel berukuran 10x1000 di halaman web. Namun, kecepatan lari mereka sangat berbeda.
/* Kode tes 1 - Waktu yang dibutuhkan: 41 detik*/
var tabel = document.createElement("TABEL");
document.body.appendChild(tabel);
untuk(var saya = 0; saya < 1000; saya++){
var baris = tabel.insertRow(-1);
untuk(var j = 0; j < 10; j++){
var sel = objRow.insertCell(-1);
sel.innerText = "( " + i + " , " + j + " )";
}
}
/* Kode pengujian 2 - Waktu yang dibutuhkan: 7,6 detik*/
var tabel = document.getElementById("TABEL");
document.body.appendChild(tabel);
var tbody = dokumen.createElement("TBODY");
tabel.appendChild(tbody);
untuk(var saya = 0; saya < 1000; saya++){
var baris = dokumen.createElement("TR");
tbody.appendChild(baris);
untuk(var j = 0; j < 10; j++){
var sel = dokumen.createElement("TD");
baris.appendChild(sel);
sel.innerText = "( " + i + " , " + j + " )";
}
}
/* Kode pengujian 3 - waktu yang dibutuhkan: 1,26 detik*/
var tbody = dokumen.createElement("TBODY");
untuk(var saya = 0; saya < 1000; saya++){
var baris = dokumen.createElement("TR");
untuk(var j = 0; j < 10; j++){
var sel = dokumen.createElement("TD");
sel.innerText = "( " + i + " , " + j + " )";
baris.appendChild(sel);
}
tbody.appendChild(baris);
}
var tabel = document.getElementById("TABEL");
tabel.appendChild(tbody);
document.body.appendChild(tabel);
Perbedaan antara "Kode Uji 1" dan "Kode Uji 2" di sini adalah metode API yang berbeda digunakan saat membuat sel tabel. Perbedaan antara "Kode Tes 2" dan "Kode Tes 3" terletak pada urutan pemrosesan yang sedikit berbeda.
Kami tidak dapat menganalisis perbedaan kinerja yang besar antara "Kode Uji 1" dan "Kode Uji 2". Yang diketahui saat ini adalah bahwa insertRow dan insertCell adalah API khusus tabel di DHTML, dan createElement serta appendChild adalah API asli W3C DOM. Yang pertama harus menjadi enkapsulasi dari yang kedua. Namun, kami tidak dapat menyimpulkan bahwa API asli DOM selalu lebih baik daripada API khusus objek. Disarankan agar Anda melakukan beberapa pengujian dasar terhadap kinerjanya ketika Anda perlu sering memanggil API.
Perbedaan performa antara "Kode Tes 2" dan "Kode Tes 3" terutama berasal dari perbedaan urutan pembuatannya. Pendekatan "Kode Uji 2" adalah dengan terlebih dahulu membuat objek <TABLE> terluar, lalu membuat <TR> dan <TD> secara berurutan dalam loop. Pendekatan "Kode Uji 3" adalah pertama-tama membangun seluruh tabel di memori dari dalam ke luar, dan kemudian menambahkannya ke halaman web. Tujuannya adalah untuk mengurangi berapa kali browser menghitung ulang tata letak halaman sebanyak mungkin. Setiap kali kita menambahkan objek ke halaman web, browser mencoba menghitung ulang tata letak kontrol pada halaman tersebut. Oleh karena itu, jika kita dapat membuat terlebih dahulu seluruh objek yang akan dibangun di memori, lalu menambahkannya ke halaman web sekaligus. Kemudian, browser hanya akan melakukan perhitungan ulang layout. Singkatnya dalam satu kalimat, semakin lama Anda menjalankan appendChild, semakin baik. Terkadang untuk meningkatkan efisiensi pengoperasian, kami bahkan dapat mempertimbangkan untuk menggunakan deleteChild untuk menghapus kontrol yang ada dari halaman, dan kemudian menempatkannya kembali ke halaman setelah konstruksi selesai.
Meningkatkan kecepatan akumulasi string. Saat menggunakan AJAX untuk mengirimkan informasi, saya mungkin sering perlu mengumpulkan beberapa string yang relatif besar untuk menyelesaikan pengiriman POST melalui XmlHttp. Meskipun menyampaikan informasi dalam jumlah besar mungkin tampak tidak sopan, terkadang kita harus menghadapi kebutuhan tersebut. Jadi seberapa cepat akumulasi string di JavaScript? Mari kita lakukan percobaan berikut terlebih dahulu. Akumulasi string dengan panjang 30000.
/* Kode pengujian 1 - Waktu yang dibutuhkan: 14,325 detik*/
varstr = "";
untuk (var saya = 0; saya < 50000; saya++) {
str+= "xxxxxx";
}
Kode ini membutuhkan waktu 14,325 detik, dan hasilnya tidak ideal. Sekarang kita ubah kodenya menjadi bentuk berikut:
/* Kode pengujian 2 - Waktu yang dibutuhkan: 0,359 detik*/
varstr = "";
untuk (var saya = 0; saya < 100; saya++) {
var sub = "";
untuk (var j = 0; j < 500; j++) {
sub+= "xxxxxx";
}
str += sub;
}
Kode ini membutuhkan waktu 0,359 detik! Hasil yang sama, yang kita lakukan hanyalah merakit beberapa string yang lebih kecil terlebih dahulu dan kemudian merakitnya menjadi string yang lebih besar. Pendekatan ini dapat secara efektif mengurangi jumlah data yang disalin ke memori pada tahap selanjutnya dari perakitan string. Setelah mengetahui prinsip ini, kita bisa membongkar lebih lanjut kode di atas untuk pengujian. Kode di bawah ini hanya membutuhkan waktu 0,140 detik.
/* Kode pengujian 3 - Waktu yang dibutuhkan: 0,140 detik*/
varstr = "";
untuk (var i1 = 0; i1 < 5; i1++) {
var str1 = "";
untuk (var i2 = 0; i2 < 10; i2++) {
var str2 = "";
untuk (var i3 = 0; i3 < 10; i3++) {
var str3 = "";
untuk (var i4 = 0; i4 < 10; i4++) {
var str4 = "";
untuk (var i5 = 0; i5 < 10; i5++) {
str4 += "xxxxxx";
}
str3 += str4;
}
str2 += str3;
}
str1 += str2;
}
str+= str1;
}
Namun, pendekatan di atas mungkin bukan yang terbaik! Jika informasi yang perlu kita kirimkan dalam format XML (pada kenyataannya, dalam banyak kasus, kita dapat mencoba merangkai informasi yang akan dikirimkan ke dalam format XML), kita juga dapat menemukan cara yang lebih efisien dan elegan - menggunakan objek DOM untuk merakitnya karakter untuk string kami. Paragraf berikut hanya membutuhkan waktu 0,890 detik untuk merakit sebuah string dengan panjang 950015.
/* Gunakan objek DOM untuk mengumpulkan informasi - waktu yang dibutuhkan: 0,890 detik*/
var xmlDok;
jika (Jenis browser == BROWSER_IE) {
xmlDoc = new ActiveXObject("Msxml.DOMDocument");
}
kalau tidak {
xmlDoc = dokumen.createElement("DOM");
}
var root = xmlDoc.createElement("root");
untuk (var saya = 0; saya < 50000; saya++) {
var node = xmlDoc.createElement("data");
jika (Jenis browser == BROWSER_IE) {
simpul.teks = "xxxxxx";
}
kalau tidak {
node.innerText = "xxxxxx";
}
root.appendChild(simpul);
}
xmlDoc.appendChild(root)
;
jika (Jenis browser == BROWSER_IE) {
str = xmlDoc.xml;
}
kalau tidak {
str = xmlDoc.innerHTML;
}
Hindari kebocoran memori objek DOM.
Kebocoran memori objek DOM di IE merupakan masalah yang sering diabaikan oleh developer. Namun, akibat yang ditimbulkannya sangat serius! Hal ini akan menyebabkan penggunaan memori IE terus meningkat, dan kecepatan berjalan browser secara keseluruhan akan melambat secara signifikan. Untuk beberapa halaman web yang sangat bocor, kecepatan berjalannya akan berlipat ganda meskipun disegarkan beberapa kali.
Model kebocoran memori yang lebih umum mencakup "model referensi siklik", "model fungsi penutupan", dan "model urutan penyisipan DOM". Untuk dua model kebocoran pertama, kita dapat menghindarinya dengan melakukan dereferensi saat halaman web dirusak. Sedangkan untuk "model urutan penyisipan DOM", hal ini perlu dihindari dengan mengubah beberapa kebiasaan pemrograman umum.
Informasi lebih lanjut tentang model kebocoran memori dapat ditemukan dengan cepat melalui Google, dan artikel ini tidak akan menjelaskan terlalu banyak. Namun, di sini saya merekomendasikan kepada Anda alat kecil yang dapat digunakan untuk menemukan dan menganalisis kebocoran memori halaman web - Drip. Versi terbaru saat ini adalah 0,5, dan alamat unduhannya adalah http://outofhanwell.com/ieleak/index.php.
Pemuatan tersegmentasi dan inisialisasi halaman kompleks Untuk beberapa antarmuka dalam sistem yang sangat kompleks dan tidak nyaman untuk menggunakan IFrame, kita dapat menerapkan pemuatan tersegmentasi. Misalnya, untuk antarmuka tab multi-halaman, pertama-tama kita dapat mengunduh dan menginisialisasi halaman default dari tab multi-halaman, lalu menggunakan teknologi AJAH (Asynchronous JavaScript and HTML) untuk memuat konten di halaman tab lain secara asinkron. Hal ini memastikan bahwa antarmuka dapat ditampilkan kepada pengguna sejak awal. Membubarkan proses pemuatan seluruh antarmuka yang kompleks ke dalam proses operasi pengguna.
Gunakan GZIP untuk mengompresi lalu lintas jaringan.
Selain peningkatan tingkat kode yang disebutkan di atas, kita juga dapat menggunakan GZIP untuk mengurangi lalu lintas jaringan secara efektif. Saat ini, semua browser umum sudah mendukung algoritma GZIP. Seringkali kita hanya perlu menulis sejumlah kecil kode untuk mendukung GZIP. Misalnya, di J2EE kita dapat menggunakan kode berikut di Filter untuk menentukan apakah browser klien mendukung algoritma GZIP, dan kemudian menggunakan java.util.zip.GZIPOutputStream untuk mengimplementasikan output GZIP sesuai kebutuhan.
/* Kode untuk menentukan bagaimana browser mendukung GZIP*/
String statis pribadi getGZIPEncoding(permintaan HttpServletRequest) {
String terimaEncoding = permintaan.getHeader("Terima-Encoding");
jika (acceptEncoding == null) mengembalikan nol;
terimaEncoding = terimaEncoding.toLowerCase();
if (acceptEncoding.indexOf("x-gzip") >= 0) kembalikan "x-gzip";
if (acceptEncoding.indexOf("gzip") >= 0) kembalikan "gzip";
kembalikan nol;
}
Secara umum, rasio kompresi GZIP untuk HTML dan JSP dapat mencapai sekitar 80%, dan hilangnya kinerja yang ditimbulkannya pada server dan klien hampir dapat diabaikan. Dikombinasikan dengan faktor-faktor lain, situs web yang mendukung GZIP dapat menghemat 50% lalu lintas jaringan. Oleh karena itu, penggunaan GZIP dapat memberikan peningkatan kinerja yang signifikan pada aplikasi yang lingkungan jaringannya tidak terlalu baik. Dengan menggunakan Fiddler, alat pemantauan HTTP, Anda dapat dengan mudah mendeteksi jumlah data komunikasi di halaman web sebelum dan sesudah menggunakan GZIP. Alamat pengunduhan Fiddler adalah http://www.fiddlertool.com /fiddler/
Optimalisasi kinerja aplikasi web sebenarnya merupakan topik yang sangat besar. Karena terbatasnya ruang, artikel ini hanya dapat membahas beberapa detail, dan juga tidak dapat sepenuhnya menunjukkan kepada Anda metode pengoptimalan detail tersebut. Saya harap artikel ini dapat menarik perhatian semua orang terhadap aplikasi Web, khususnya optimasi kinerja sisi klien. Bagaimanapun, teknik pemrograman sisi server telah diketahui semua orang selama bertahun-tahun, dan tidak banyak potensi untuk memanfaatkan kinerja di sisi server. Peningkatan metode di sisi klien sering kali dapat menghasilkan peningkatan kinerja yang mengejutkan.