เพิ่มประสิทธิภาพการเรียกใช้ JavaScript

JavaScript มักทำให้เกิดการเปลี่ยนแปลงด้านรูปลักษณ์ บางครั้งก็เกิดจากการดัดแปลงสไตล์โดยตรง และบางครั้งก็เป็นการคำนวณที่ส่งผลให้เกิดการเปลี่ยนแปลงของภาพ เช่น การค้นหาหรือการจัดเรียงข้อมูล JavaScript ที่ทำงานช้าหรือใช้เวลานานคือสาเหตุที่พบบ่อยของปัญหาด้านประสิทธิภาพ คุณควรพยายามลดผลกระทบให้เหลือน้อยที่สุดเท่าที่ทำได้

พอล ลูอิส
Paul Lewis

JavaScript มักทำให้เกิดการเปลี่ยนแปลงด้านรูปลักษณ์ บางครั้งก็มาจากการดัดแปลงสไตล์โดยตรง และบางครั้งก็เป็นการคำนวณที่ส่งผลให้เกิดการเปลี่ยนแปลงของภาพ เช่น การค้นหาหรือการจัดเรียงข้อมูล JavaScript ที่ทำงานช้าหรือใช้เวลานานเป็นสาเหตุที่พบบ่อยของปัญหาด้านประสิทธิภาพ คุณควรพยายามลดผลกระทบให้เหลือน้อยที่สุดเท่าที่ทำได้

การทำโปรไฟล์ประสิทธิภาพของ JavaScript อาจเป็นศิลปะอย่างที่ควรจะเป็น เพราะ JavaScript ที่คุณเขียนไม่ใช่โค้ดที่เรียกใช้จริงๆ เบราว์เซอร์ที่ทันสมัยใช้คอมไพเลอร์ JIT รวมถึงการเพิ่มประสิทธิภาพและกลเม็ดในลักษณะต่างๆ เพื่อพยายามดำเนินการให้รวดเร็วที่สุด และสิ่งนี้จะเปลี่ยนแปลงการเปลี่ยนแปลงของโค้ดไปอย่างมาก

อย่างไรก็ตาม มีบางอย่างที่คุณทำได้แน่นอนเพื่อช่วยให้แอปทำงานได้กับ JavaScript

สรุป

  • หลีกเลี่ยง setTimeout หรือ setInterval สำหรับการอัปเดตภาพ ให้ใช้ requestAnimationFrame แทนเสมอ
  • ย้าย JavaScript ที่ทํางานเป็นเวลานานออกจากเทรดหลักไปยัง Web Worker
  • ใช้งานไมโครเพื่อทำการเปลี่ยนแปลง DOM ในเฟรมหลายรายการ
  • ใช้ไทม์ไลน์ของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome และเครื่องมือสร้างโปรไฟล์ JavaScript เพื่อประเมินผลกระทบของ JavaScript

ใช้ requestAnimationFrame เพื่อเปลี่ยนภาพ

เมื่อเกิดการเปลี่ยนแปลงด้านภาพบนหน้าจอ คุณจะต้องทำงานในช่วงเวลาที่เหมาะสมสำหรับเบราว์เซอร์ ซึ่งอยู่ ณ จุดเริ่มต้นของเฟรม วิธีเดียวที่จะทำให้ JavaScript ทำงานได้ที่จุดเริ่มต้นของเฟรมคือการใช้ 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);

เฟรมเวิร์กหรือตัวอย่างอาจใช้ setTimeout หรือ setInterval เพื่อทำการเปลี่ยนแปลงภาพ เช่น ภาพเคลื่อนไหว แต่ปัญหาในกรณีนี้คือโค้ดเรียกกลับจะทำงานที่บางจุดในเฟรม หรือในตอนท้าย และมักทำให้เราพลาดเฟรม ซึ่งส่งผลให้ภาพติดขัด

setTimeout ทําให้เบราว์เซอร์พลาดเฟรม

อันที่จริง jQuery เคยใช้ setTimeout สำหรับลักษณะการทำงาน animate เปลี่ยนไปใช้ requestAnimationFrame ในเวอร์ชัน 3 หากคุณใช้ jQuery เวอร์ชันเก่า คุณสามารถแพตช์เพื่อใช้ requestAnimationFrame ได้ ซึ่งเป็นสิ่งที่ควรทำ

ลดความซับซ้อนหรือใช้ Web Worker

JavaScript จะทำงานบนเทรดหลักของเบราว์เซอร์ ควบคู่ไปกับการคำนวณสไตล์ เลย์เอาต์ และในหลายกรณี ก็ใช้ Paint ได้ หาก JavaScript ทำงานเป็นเวลานาน JavaScript จะบล็อกงานอื่นๆ เหล่านี้ ซึ่งอาจส่งผลให้เฟรมหายไป

คุณควรใช้กลยุทธ์เกี่ยวกับเวลาที่ JavaScript ทำงานและระยะเวลาในการทำงาน เช่น หากคุณอยู่ในภาพเคลื่อนไหว เช่น การเลื่อน คุณควรกำหนดให้ JavaScript มีความยาวเท่าใดในช่วง 3-4 มิลลิวินาที หากยาวกว่านั้นจะทำให้ใช้เวลานานเกินไป หากอยู่ในช่วงที่ไม่มีการใช้งาน คุณก็สบายใจได้มากเกี่ยวกับเวลาที่ใช้ไป

ในหลายๆ กรณี คุณสามารถย้ายงานด้านการประมวลผลอย่างเดียวไปยัง Web Worker ในกรณีที่ไม่ต้องใช้การเข้าถึง DOM เป็นต้น การควบคุมหรือการส่งผ่านข้อมูล เช่น การจัดเรียงหรือการค้นหา มักเหมาะกับโมเดลนี้ เช่นเดียวกับการโหลดและการสร้างโมเดล

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...
});

บางงานอาจไม่เหมาะกับโมเดลนี้ เนื่องจาก Web Worker ไม่มีสิทธิ์เข้าถึง DOM เมื่องานต้องอยู่ในเทรดหลัก ให้ลองใช้วิธีการแบบกลุ่ม โดยที่คุณแบ่งกลุ่มงานขนาดใหญ่ออกเป็นงานย่อยๆ งานแต่ละชิ้นใช้เวลาไม่เกิน 2-3 มิลลิวินาที และทำงานภายในเครื่องจัดการ requestAnimationFrame ในแต่ละเฟรม

วิธีนี้ทำให้เกิด UX และ UI และคุณจะต้องตรวจสอบว่าผู้ใช้ทราบว่าระบบกำลังประมวลผลงาน ไม่ว่าจะโดยการใช้ตัวบ่งชี้ความคืบหน้าหรือสัญญาณบอกสถานะกิจกรรม ไม่ว่าในกรณีใดก็ตาม วิธีนี้จะทําให้เทรดหลักของแอปใช้งานได้ฟรี ซึ่งจะช่วยคงการตอบสนองต่อการโต้ตอบของผู้ใช้

ศึกษา "ภาษีเฟรม" ของ JavaScript

เมื่อประเมินเฟรมเวิร์ก ไลบรารี หรือโค้ดของคุณเอง คุณจำเป็นต้องประเมินค่าใช้จ่ายในการเรียกใช้โค้ด JavaScript แบบเฟรมต่อเฟรม ซึ่งสำคัญมากเมื่อทำงานภาพเคลื่อนไหวที่สำคัญมาก เช่น การเปลี่ยนภาพหรือการเลื่อน

แผงประสิทธิภาพของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เป็นวิธีที่ดีที่สุดในการวัดค่าใช้จ่ายของ JavaScript โดยปกติ คุณจะได้รับระเบียนระดับต่ำดังนี้

การบันทึกประสิทธิภาพในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

ส่วนหลักมีแผนภูมิเปลวไฟของการเรียกใช้ JavaScript เพื่อให้คุณวิเคราะห์ได้อย่างชัดเจนว่าฟังก์ชันใดที่มีการเรียกและระยะเวลาที่ใช้

ข้อมูลนี้จะช่วยให้คุณประเมินผลกระทบด้านประสิทธิภาพที่ JavaScript มีต่อแอปพลิเคชัน และเริ่มค้นหาและแก้ไขฮอตสปอตที่ฟังก์ชันใช้เวลาประมวลผลนานเกินไปได้ ตามที่ได้กล่าวไว้ก่อนหน้านี้ คุณควรนำ JavaScript ที่ใช้เวลานานออก หรือหากทำไม่ได้ ให้ย้ายไปยัง Web Worker เพื่อให้มีเทรดหลักเพื่อทำงานอื่นๆ ต่อ

ดูเริ่มต้นใช้งานการวิเคราะห์ประสิทธิภาพรันไทม์เพื่อเรียนรู้วิธีใช้แผงประสิทธิภาพ

หลีกเลี่ยงการเพิ่มประสิทธิภาพ JavaScript แบบไมโคร

อาจดีที่รู้ว่าเบราว์เซอร์สามารถดำเนินการกับเวอร์ชันหนึ่งได้เร็วกว่าเวอร์ชันอื่นถึง 100 เท่า เช่น การขอ offsetTop ขององค์ประกอบนั้นเร็วกว่าการประมวลผล getBoundingClientRect() แต่ส่วนใหญ่แล้วคุณจะเรียกใช้ฟังก์ชันต่างๆ เหล่านี้เพียงไม่กี่ครั้งต่อเฟรมเท่านั้น ตามปกติคุณจึงต้องใช้เวลาทุ่มเทกับการทำงานด้านนี้ของ JavaScript เท่านั้น โดยทั่วไปคุณจะประหยัดเวลาได้เพียงเศษเสี้ยวของมิลลิวินาที

หากคุณกำลังสร้างเกมหรือแอปพลิเคชันสำหรับการประมวลผลที่มีราคาแพง ก็มีแนวโน้มที่จะมีข้อยกเว้นสำหรับคำแนะนำนี้ เนื่องจากโดยทั่วไปแล้วคุณจะผสมผสานการคำนวณจำนวนมากไว้ในเฟรมเดียว และในกรณีนี้ ทุกสิ่งมีส่วนช่วยได้

พูดง่ายๆ ก็คือคุณควรระมัดระวังการเพิ่มประสิทธิภาพแบบไมโครเพราะจะไม่ได้จับคู่กับประเภทแอปพลิเคชันที่คุณกำลังสร้าง