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

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

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

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

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

สรุป

  • หลีกเลี่ยงการใช้ setTimeout หรือ setInterval สำหรับการอัปเดตภาพ ให้ใช้ requestAnimationFrame แทนเสมอ
  • ย้าย JavaScript ที่ทำงานเป็นเวลานานออกจากเทรดหลักไปยัง Web Worker
  • ใช้ไมโครแทสก์เพื่อทําการเปลี่ยนแปลง DOM ในหลายเฟรม
  • ใช้ไทม์ไลน์และเครื่องมือวิเคราะห์ JavaScript ของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เพื่อประเมินผลกระทบของ 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 เพื่อทําการเปลี่ยนแปลงภาพ เช่น ภาพเคลื่อนไหว แต่ปัญหาของวิธีนี้คือ Callback จะทํางานเมื่อใดเวลาหนึ่งในเฟรม ซึ่งอาจเป็นตอนท้ายเลยก็ได้ และมักจะทําให้เราพลาดเฟรมหนึ่งๆ ซึ่งส่งผลให้ภาพกระตุก

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

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

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

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 จึงเป็นเรื่องที่เสียเปล่า โดยปกติแล้วคุณจะประหยัดเวลาได้เพียงเศษเสี้ยวของมิลลิวินาที

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

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