การเกิดขึ้นของ AJAX ได้เปลี่ยนแปลงโหมดการทำงานของไคลเอ็นต์แอปพลิเคชันเว็บไปอย่างมาก ช่วยให้ผู้ใช้สามารถมุ่งความสนใจไปที่งานของตนได้โดยไม่ต้องทนกับการรีเฟรชเพจที่น่ารำคาญบ่อยครั้ง ตามทฤษฎีแล้ว เทคโนโลยี AJAX สามารถลดเวลารอคอยในการดำเนินการของผู้ใช้ได้อย่างมาก และประหยัดการรับส่งข้อมูลบนเครือข่าย อย่างไรก็ตาม นี่ไม่ใช่กรณีเสมอไป ผู้ใช้มักบ่นว่าความเร็วในการตอบสนองของระบบที่ใช้ AJAX ลดลง
ผู้เขียนมีส่วนร่วมในการวิจัยและพัฒนา AJAX มาหลายปี และมีส่วนร่วมในการพัฒนา dorado ซึ่งเป็นแพลตฟอร์ม AJAX ที่ค่อนข้างเติบโตในประเทศจีน ตามประสบการณ์ของผู้เขียน สาเหตุของผลลัพธ์นี้ไม่ใช่ AJAX หลายครั้งที่ความเร็วตอบสนองของระบบลดลงเกิดจากการออกแบบอินเทอร์เฟซที่ไม่สมเหตุสมผลและพฤติกรรมการเขียนโปรแกรมที่มีประสิทธิภาพไม่เพียงพอ ด้านล่างนี้เราจะวิเคราะห์แง่มุมต่างๆ ที่ต้องให้ความสนใจในระหว่างกระบวนการพัฒนา AJAX
การใช้โปรแกรมไคลเอนต์และการเรียกขั้นตอนระยะไกลอย่างเหมาะสม
การเขียนโปรแกรมฝั่งไคลเอ็นต์ใช้ JavaScript เป็นหลัก JavaScript เป็นภาษาการเขียนโปรแกรมแบบตีความ และประสิทธิภาพการทำงานของมันต่ำกว่า Java เล็กน้อย ในเวลาเดียวกัน JavaScript ทำงานในสภาพแวดล้อมที่จำกัดอย่างเข้มงวด เช่น เบราว์เซอร์ ดังนั้นนักพัฒนาควรมีความเข้าใจที่ชัดเจนว่าตรรกะใดที่สามารถดำเนินการได้บนฝั่งไคลเอ็นต์
วิธีใช้การเขียนโปรแกรมฝั่งไคลเอ็นต์ในแอปพลิเคชันจริงนั้นขึ้นอยู่กับประสบการณ์และวิจารณญาณของนักพัฒนา ปัญหามากมายที่นี่สามารถเข้าใจได้เท่านั้น เนื่องจากพื้นที่จำกัด เราจึงสรุปข้อควรระวังต่อไปนี้โดยคร่าว:
หลีกเลี่ยงการใช้การเรียกขั้นตอนระยะไกลบ่อยครั้งให้มากที่สุดเท่าที่จะเป็นไปได้ เช่น หลีกเลี่ยงการใช้การเรียกขั้นตอนระยะไกลในเนื้อความของลูป
หากเป็นไปได้ ให้ใช้การเรียกขั้นตอนระยะไกล AJAX (การเรียกขั้นตอนระยะไกลแบบอะซิงโครนัส)
หลีกเลี่ยงการวางการดำเนินการกับข้อมูลขนาดใหญ่บนฝั่งไคลเอ็นต์ ตัวอย่างเช่น: การคัดลอกข้อมูลจำนวนมาก การคำนวณที่ต้องใช้การข้ามผ่านข้อมูลจำนวนมาก เป็นต้น
ปรับปรุงวิธีการทำงานของวัตถุ DOM
ในการเขียนโปรแกรมฝั่งไคลเอ็นต์ การดำเนินการบนออบเจ็กต์ DOM มักจะใช้เวลา CPU มากที่สุด สำหรับการทำงานของออบเจ็กต์ DOM ความแตกต่างด้านประสิทธิภาพระหว่างวิธีการเขียนโปรแกรมต่างๆ มักจะมีขนาดใหญ่มาก
ต่อไปนี้เป็นโค้ดสามชิ้นที่มีผลลัพธ์เหมือนกันทุกประการ ฟังก์ชันของพวกเขาคือการสร้างตารางขนาด 10x1000 ในหน้าเว็บ อย่างไรก็ตาม ความเร็วในการวิ่งนั้นแตกต่างกันมาก
/* รหัสทดสอบ 1 - เวลาที่ใช้: 41 วินาที*/
var table = document.createElement("ตาราง");
document.body.appendChild (ตาราง);
สำหรับ (var i = 0; i < 1,000; i++){
var แถว = table.insertRow(-1);
สำหรับ(var j = 0; j < 10; j++){
เซลล์ var = objRow.insertCell(-1);
cell.innerText = "( " + i + " , " + j + " )";
-
}
/* รหัสทดสอบ 2 - เวลาที่ใช้: 7.6 วินาที*/
ตาราง var = document.getElementById("ตาราง");
document.body.appendChild (ตาราง);
var tbody = document.createElement("TBODY");
table.appendChild (tbody);
สำหรับ (var i = 0; i < 1,000; i++){
แถว var = document.createElement("TR");
tbody.appendChild (แถว);
สำหรับ(var j = 0; j < 10; j++){
เซลล์ var = document.createElement("TD");
row.appendChild (เซลล์);
cell.innerText = "( " + i + " , " + j + " )";
-
}
/* รหัสทดสอบ 3 - เวลาที่ใช้: 1.26 วินาที*/
var tbody = document.createElement("TBODY");
สำหรับ (var i = 0; i < 1,000; i++){
แถว var = document.createElement("TR");
สำหรับ(var j = 0; j < 10; j++){
เซลล์ var = document.createElement("TD");
cell.innerText = "( " + i + " , " + j + " )";
row.appendChild (เซลล์);
-
tbody.appendChild (แถว);
-
ตาราง var = document.getElementById("ตาราง");
table.appendChild (tbody);
document.body.appendChild (ตาราง);
ความแตกต่างระหว่าง "รหัสทดสอบ 1" และ "รหัสทดสอบ 2" คือมีการใช้วิธี API ที่แตกต่างกันในการสร้างเซลล์ตาราง ความแตกต่างระหว่าง "รหัสทดสอบ 2" และ "รหัสทดสอบ 3" อยู่ที่ลำดับการประมวลผลที่แตกต่างกันเล็กน้อย
เราไม่สามารถวิเคราะห์ความแตกต่างด้านประสิทธิภาพขนาดใหญ่ระหว่าง "Test Code 1" และ "Test Code 2" ได้ สิ่งที่ทราบในปัจจุบันคือ insertRow และ insertCell เป็น API เฉพาะตารางใน DHTML และ createElement และ appendChild เป็น API ดั้งเดิมของ W3C DOM อันแรกควรเป็นการห่อหุ้มอันหลัง อย่างไรก็ตาม เราไม่สามารถสรุปได้ว่า API ดั้งเดิมของ DOM นั้นดีกว่า API เฉพาะวัตถุเสมอไป ขอแนะนำให้คุณทำการทดสอบพื้นฐานเกี่ยวกับประสิทธิภาพเมื่อคุณต้องการเรียกใช้ API บ่อยครั้ง
ความแตกต่างด้านประสิทธิภาพระหว่าง "รหัสทดสอบ 2" และ "รหัสทดสอบ 3" ส่วนใหญ่มาจากความแตกต่างในลำดับการสร้าง วิธีการของ "รหัสทดสอบ 2" คือการสร้างวัตถุ <TABLE> ภายนอกสุดก่อน จากนั้นจึงสร้าง <TR> และ <TD> ตามลำดับในลูป แนวทางของ "Test Code 3" คือการสร้างตารางทั้งหมดในหน่วยความจำจากภายในสู่ภายนอกก่อน จากนั้นจึงเพิ่มลงในหน้าเว็บ จุดประสงค์คือเพื่อลดจำนวนครั้งที่เบราว์เซอร์คำนวณเค้าโครงหน้าใหม่ให้มากที่สุด เมื่อใดก็ตามที่เราเพิ่มออบเจ็กต์ลงในเว็บเพจ เบราว์เซอร์จะพยายามคำนวณเค้าโครงของตัวควบคุมบนเพจใหม่ ดังนั้นหากเราสามารถสร้าง object ทั้งหมดขึ้นมาในหน่วยความจำได้ก่อนแล้วค่อยเพิ่มเข้าเว็บเพจในคราวเดียว จากนั้นเบราว์เซอร์จะทำการคำนวณเค้าโครงใหม่เท่านั้น เพื่อสรุปเป็นประโยคเดียว ยิ่งคุณรัน appendChild ช้าเท่าไรก็ยิ่งดีเท่านั้น บางครั้งเพื่อปรับปรุงประสิทธิภาพการดำเนินงาน เราอาจพิจารณาใช้ RemoveChild เพื่อลบการควบคุมที่มีอยู่ออกจากเพจ จากนั้นจึงวางกลับเข้าไปในเพจอีกครั้งหลังจากการก่อสร้างเสร็จสมบูรณ์
ปรับปรุงความเร็วของการสะสมสตริง เมื่อใช้ AJAX เพื่อส่งข้อมูล ฉันมักจะต้องรวบรวมสตริงที่ค่อนข้างใหญ่เพื่อให้การส่ง POST ผ่าน XmlHttp เสร็จสมบูรณ์ แม้ว่าการส่งข้อมูลจำนวนมากอาจดูไม่สวยงาม แต่บางครั้งเราอาจต้องเผชิญกับความจำเป็นดังกล่าว การสะสมสตริงใน JavaScript เร็วแค่ไหน? เรามาทำการทดลองต่อไปนี้กันก่อน สะสมสตริงที่มีความยาว 30000
/* รหัสทดสอบ 1 - เวลาที่ใช้: 14.325 วินาที*/
var str = "";
สำหรับ (var i = 0; i < 50,000; i++) {
STR += "xxxxxx";
-
รหัสนี้ใช้เวลา 14.325 วินาที และผลลัพธ์ไม่เหมาะ ตอนนี้เราเปลี่ยนรหัสเป็นรูปแบบต่อไปนี้:
/* รหัสทดสอบ 2 - เวลาที่ใช้: 0.359 วินาที*/
var str = "";
สำหรับ (var i = 0; i < 100; i++) {
var ย่อย = "";
สำหรับ (var j = 0; j <500; j++) {
ย่อย += "xxxxxx";
-
STR += ย่อย;
-
รหัสนี้ใช้เวลา 0.359 วินาที! ผลลัพธ์เดียวกัน สิ่งที่เราทำคือประกอบสายเล็กๆ ก่อนแล้วจึงประกอบเป็นสายที่ใหญ่ขึ้น วิธีการนี้สามารถลดจำนวนข้อมูลที่คัดลอกในหน่วยความจำในระยะหลังของแอสเซมบลีสตริงได้อย่างมีประสิทธิภาพ หลังจากทราบหลักการนี้แล้ว เราก็สามารถรื้อโค้ดด้านบนเพื่อทำการทดสอบเพิ่มเติมได้ รหัสด้านล่างใช้เวลาเพียง 0.140 วินาที
/* รหัสทดสอบ 3 - เวลาที่ใช้: 0.140 วินาที*/
var str = "";
สำหรับ (var i1 = 0; i1 < 5; i1++) {
var str1 = "";
สำหรับ (var i2 = 0; i2 < 10; i2++) {
var str2 = "";
สำหรับ (var i3 = 0; i3 < 10; i3++) {
var str3 = "";
สำหรับ (var i4 = 0; i4 <10; i4++) {
var str4 = "";
สำหรับ (var i5 = 0; i5 < 10; i5++) {
str4 += "xxxxxx";
-
str3 += str4;
-
str2 += str3;
-
str1 += str2;
-
STR += str1;
-
อย่างไรก็ตาม วิธีการข้างต้นอาจไม่ใช่วิธีที่ดีที่สุด! หากข้อมูลที่เราต้องส่งอยู่ในรูปแบบ XML (อันที่จริงแล้ว ในกรณีส่วนใหญ่ เราสามารถลองรวบรวมข้อมูลที่จะส่งเป็นรูปแบบ XML ได้) เราก็สามารถหาวิธีที่มีประสิทธิภาพและสวยงามยิ่งขึ้นได้ - โดยใช้วัตถุ DOM ในการประกอบ อักขระสำหรับเราสตริง ย่อหน้าต่อไปนี้ใช้เวลาเพียง 0.890 วินาทีในการประกอบสตริงที่มีความยาว 950015
/* ใช้วัตถุ DOM เพื่อรวบรวมข้อมูล - เวลาที่ใช้: 0.890 วินาที*/
var xmlDoc;
ถ้า (ประเภทเบราว์เซอร์ == BROWSER_IE) {
xmlDoc = ใหม่ ActiveXObject("Msxml.DOMDocument");
-
อื่น {
xmlDoc = document.createElement("DOM");
-
var root = xmlDoc.createElement("รูท");
สำหรับ (var i = 0; i < 50,000; i++) {
โหนด var = xmlDoc.createElement("ข้อมูล");
ถ้า (ประเภทเบราว์เซอร์ == BROWSER_IE) {
node.text = "xxxxxx";
-
อื่น {
node.innerText = "xxxxxx";
-
root.appendChild (โหนด);
-
xmlDoc.appendChild(ราก)
;
ถ้า (ประเภทเบราว์เซอร์ == BROWSER_IE) {
str = xmlDoc.xml;
-
อื่น {
str = xmlDoc.innerHTML;
}
หลีกเลี่ยงการรั่วไหลของหน่วยความจำของวัตถุ DOM
หน่วยความจำรั่วของวัตถุ DOM ใน IE เป็นปัญหาที่นักพัฒนามักมองข้าม อย่างไรก็ตาม ผลที่ตามมานั้นร้ายแรงมาก! จะทำให้การใช้หน่วยความจำของ IE เพิ่มขึ้นอย่างต่อเนื่อง และความเร็วในการทำงานโดยรวมของเบราว์เซอร์ช้าลงอย่างมาก สำหรับหน้าเว็บที่มีการรั่วไหลร้ายแรงบางหน้า ความเร็วในการทำงานจะเพิ่มเป็นสองเท่าแม้ว่าจะรีเฟรชสองสามครั้งก็ตาม
โมเดลการรั่วไหลของหน่วยความจำที่พบบ่อย ได้แก่ "โมเดลอ้างอิงแบบวน" "โมเดลฟังก์ชันการปิด" และ "โมเดลลำดับการแทรก DOM" สำหรับโมเดลการรั่วไหลสองแบบแรก เราสามารถหลีกเลี่ยงได้โดยการยกเลิกการอ้างอิงเมื่อหน้าเว็บถูกทำลาย สำหรับ "โมเดลลำดับการแทรก DOM" จะต้องหลีกเลี่ยงโดยการเปลี่ยนพฤติกรรมการเขียนโปรแกรมทั่วไปบางอย่าง
ข้อมูลเพิ่มเติมเกี่ยวกับโมเดลการรั่วไหลของหน่วยความจำสามารถพบได้อย่างรวดเร็วผ่าน Google และบทความนี้จะไม่อธิบายรายละเอียดมากเกินไป อย่างไรก็ตาม ฉันขอแนะนำเครื่องมือเล็กๆ ให้คุณใช้ค้นหาและวิเคราะห์การรั่วไหลของหน่วยความจำหน้าเว็บได้ - Drip เวอร์ชันใหม่กว่าปัจจุบันคือ 0.5 และที่อยู่การดาวน์โหลดคือ http://outofhanwell.com/ieleak/index.php
การโหลดแบบแบ่งส่วนและการเริ่มต้นของเพจที่ซับซ้อน สำหรับอินเทอร์เฟซบางอย่างในระบบที่ซับซ้อนมากและไม่สะดวกในการใช้ IFrame เราสามารถใช้การโหลดแบบแบ่งส่วนได้ ตัวอย่างเช่น สำหรับอินเทอร์เฟซแท็บหลายหน้า ขั้นแรกเราสามารถดาวน์โหลดและเริ่มต้นหน้าเริ่มต้นของแท็บหลายหน้า จากนั้นใช้เทคโนโลยี AJAH (JavaScript แบบอะซิงโครนัสและ HTML) เพื่อโหลดเนื้อหาในหน้าแท็บอื่นแบบอะซิงโครนัส เพื่อให้แน่ใจว่าอินเทอร์เฟซสามารถแสดงต่อผู้ใช้ได้ตั้งแต่แรก แยกย้ายกระบวนการโหลดของอินเทอร์เฟซที่ซับซ้อนทั้งหมดไปยังกระบวนการดำเนินการของผู้ใช้
ใช้ GZIP เพื่อบีบอัดการรับส่งข้อมูลเครือข่าย
นอกจากการปรับปรุงระดับโค้ดที่กล่าวถึงข้างต้นแล้ว เรายังสามารถใช้ GZIP เพื่อลดการรับส่งข้อมูลเครือข่ายได้อย่างมีประสิทธิภาพ ในปัจจุบัน เบราว์เซอร์กระแสหลักทั่วไปทั้งหมดรองรับอัลกอริธึม GZIP แล้ว เรามักจะต้องเขียนโค้ดเพียงเล็กน้อยเพื่อรองรับ GZIP ตัวอย่างเช่น ใน J2EE เราสามารถใช้โค้ดต่อไปนี้ใน Filter เพื่อตรวจสอบว่าเบราว์เซอร์ไคลเอ็นต์รองรับอัลกอริทึม GZIP หรือไม่ จากนั้นใช้ java.util.zip.GZIPOutputStream เพื่อใช้เอาต์พุต GZIP ตามต้องการ
/* รหัสเพื่อกำหนดวิธีที่เบราว์เซอร์รองรับ GZIP*/
สตริงคงที่ส่วนตัว getGZIPencoding (คำขอ HttpServletRequest) {
สตริง AcceptEncoding = request.getHeader("ยอมรับการเข้ารหัส");
ถ้า (acceptEncoding == null) ส่งคืน null;
AcceptEncoding = AcceptEncoding.toLowerCase();
ถ้า (acceptEncoding.indexOf("x-gzip") >= 0) ส่งคืน "x-gzip";
ถ้า (acceptEncoding.indexOf("gzip") >= 0) ส่งคืน "gzip";
กลับเป็นโมฆะ;
-
โดยทั่วไปแล้ว อัตราการบีบอัดของ GZIP สำหรับ HTML และ JSP สามารถเข้าถึงได้ประมาณ 80% และการสูญเสียประสิทธิภาพที่เกิดขึ้นบนเซิร์ฟเวอร์และไคลเอนต์นั้นแทบไม่มีนัยสำคัญเลย เมื่อรวมกับปัจจัยอื่นๆ เว็บไซต์ที่รองรับ GZIP อาจช่วยเราประหยัดการรับส่งข้อมูลเครือข่ายได้ 50% ดังนั้น การใช้ GZIP สามารถนำมาซึ่งการปรับปรุงประสิทธิภาพที่สำคัญให้กับแอปพลิเคชันที่สภาพแวดล้อมเครือข่ายไม่ดีเป็นพิเศษ การใช้ Fiddler ซึ่งเป็นเครื่องมือตรวจสอบ HTTP ทำให้คุณสามารถตรวจจับจำนวนข้อมูลการสื่อสารบนหน้าเว็บก่อนและหลังการใช้ GZIP ได้อย่างง่ายดาย ที่อยู่การดาวน์โหลดของ Fiddler คือ http://www.fiddlertool.com /fiddler/
การเพิ่มประสิทธิภาพการทำงานของเว็บแอปพลิเคชันถือเป็นหัวข้อใหญ่จริงๆ เนื่องจากมีพื้นที่จำกัด บทความนี้จึงครอบคลุมรายละเอียดได้เพียงบางส่วนเท่านั้น และไม่สามารถแสดงวิธีการเพิ่มประสิทธิภาพของรายละเอียดเหล่านี้ได้ทั้งหมด ฉันหวังว่าบทความนี้สามารถดึงความสนใจของทุกคนมายังเว็บแอปพลิเคชันได้ โดยเฉพาะการเพิ่มประสิทธิภาพฝั่งไคลเอ็นต์ ท้ายที่สุดแล้ว ทุกคนรู้จักเทคนิคการเขียนโปรแกรมฝั่งเซิร์ฟเวอร์มาหลายปีแล้ว และไม่มีศักยภาพมากนักในการใช้ประโยชน์จากประสิทธิภาพบนฝั่งเซิร์ฟเวอร์ การปรับปรุงวิธีการในฝั่งไคลเอ็นต์มักจะนำไปสู่การปรับปรุงประสิทธิภาพที่น่าประหลาดใจ