เพิ่มประสิทธิภาพงานที่ใช้เวลานาน

คุณเคยได้ยินว่า "อย่าบล็อกเธรดหลัก" และ "แบ่งงานที่มีระยะเวลานาน" แต่การทําเช่นนั้นหมายความว่าอย่างไร

คำแนะนำทั่วไปในการทำให้แอป JavaScript ทำงานได้อย่างรวดเร็วมักจะสรุปเป็นคำแนะนำต่อไปนี้

  • "อย่าบล็อกชุดข้อความหลัก"
  • "แบ่งงานใหญ่ออกเป็นงานย่อยๆ"

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

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

งานคืออะไร

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

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

งานที่เกี่ยวข้องกับ JavaScript จะส่งผลต่อประสิทธิภาพใน 2 วิธีดังนี้

  • เมื่อเบราว์เซอร์ดาวน์โหลดไฟล์ JavaScript ระหว่างการเริ่มต้น เบราว์เซอร์จะจัดคิวงานเพื่อแยกวิเคราะห์และคอมไพล์ JavaScript นั้นเพื่อให้สามารถเรียกใช้ได้ในภายหลัง
  • ในช่วงเวลาอื่นๆ ของอายุหน้าเว็บ ระบบจะจัดคิวงานเมื่อ JavaScript ทํางาน เช่น กระตุ้นการโต้ตอบผ่านตัวแฮนเดิลเหตุการณ์ ภาพเคลื่อนไหวที่ขับเคลื่อนโดย JavaScript และกิจกรรมเบื้องหลัง เช่น การเก็บรวบรวมข้อมูลวิเคราะห์

การดำเนินการทั้งหมดนี้ (ยกเว้น Web Worker และ API ที่คล้ายกัน) จะเกิดขึ้นในเธรดหลัก

เทรดหลักคืออะไร

เธรดหลักคือที่ที่งานส่วนใหญ่ทำงานในเบราว์เซอร์ และที่ที่ JavaScript เกือบทั้งหมดที่คุณเขียนจะทำงาน

เทรดหลักจะประมวลผลงานได้ครั้งละ 1 งานเท่านั้น งานใดก็ตามที่ใช้เวลานานกว่า 50 มิลลิวินาทีถือเป็นงานที่ใช้เวลานาน สำหรับงานที่ใช้เวลานานกว่า 50 มิลลิวินาที เวลาทั้งหมดของงานลบด้วย 50 มิลลิวินาทีเรียกว่าระยะเวลาการบล็อกของงาน

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

งานที่มีระยะเวลานานในเครื่องมือวิเคราะห์ประสิทธิภาพของ DevTools ใน Chrome ส่วนการบล็อกของงาน (มากกว่า 50 มิลลิวินาที) จะแสดงด้วยลายเส้นทแยงมุมสีแดง
งานที่ใช้เวลานานตามที่แสดงในเครื่องมือวิเคราะห์ประสิทธิภาพของ Chrome งานที่มีความยาวจะแสดงด้วยรูปสามเหลี่ยมสีแดงที่มุมของงาน โดยส่วนที่บล็อกของงานจะมีลายเส้นสีแดงทแยงมุม

คุณสามารถแบ่งงานที่มีขนาดใหญ่ออกเป็นงานเล็กๆ หลายงานเพื่อป้องกันไม่ให้เทรดหลักถูกบล็อกเป็นเวลานาน

งานเดียวที่ยาวมากเทียบกับงานเดียวกันที่แบ่งออกเป็นงานสั้นๆ งานแบบยาวเป็นรูปสี่เหลี่ยมผืนผ้าขนาดใหญ่ 1 รูป ส่วนงานแบบแบ่งเป็นชิ้นๆ เป็นรูปสี่เหลี่ยมผืนผ้าขนาดเล็ก 5 รูปที่มีความกว้างรวมเท่ากับงานแบบยาว
การแสดงภาพงานยาวรายการเดียวเทียบกับงานเดียวกันที่แบ่งออกเป็นงานสั้นๆ 5 รายการ

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

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

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

เมื่อทราบความสำคัญของการแบ่งงานแล้ว คุณก็ดูวิธีดำเนินการใน JavaScript ได้

กลยุทธ์การจัดการงาน

คำแนะนำทั่วไปในสถาปัตยกรรมซอฟต์แวร์คือการแบ่งงานออกเป็นฟังก์ชันย่อยๆ ดังนี้

function saveSettings () {
  validateForm
();
  showSpinner
();
  saveToDatabase
();
  updateUI
();
  sendAnalytics
();
}

ในตัวอย่างนี้ มีฟังก์ชันชื่อ saveSettings() ที่เรียกใช้ฟังก์ชัน 5 รายการเพื่อตรวจสอบแบบฟอร์ม แสดงภาพสปินเนอร์ ส่งข้อมูลไปยังแบ็กเอนด์ของแอปพลิเคชัน อัปเดตอินเทอร์เฟซผู้ใช้ และส่งข้อมูลวิเคราะห์

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

อย่างไรก็ตาม ปัญหาที่อาจเกิดขึ้นคือ JavaScript จะไม่เรียกใช้ฟังก์ชันเหล่านี้แต่ละรายการเป็นงานที่แยกกัน เนื่องจากจะดำเนินการภายในฟังก์ชัน saveSettings() ซึ่งหมายความว่าฟังก์ชันทั้ง 5 รายการจะทํางานเป็นงานเดียว

ฟังก์ชัน saveSettings ตามที่แสดงในเครื่องมือวิเคราะห์ประสิทธิภาพของ Chrome ขณะที่ฟังก์ชันระดับบนสุดเรียกใช้ฟังก์ชันอื่นๆ อีก 5 รายการ งานทั้งหมดจะเกิดขึ้นในภารกิจที่ยาวนานรายการเดียวซึ่งบล็อกเธรดหลัก
ฟังก์ชัน saveSettings() รายการเดียวที่เรียกใช้ฟังก์ชัน 5 รายการ งานจะทํางานเป็นส่วนหนึ่งของงานแบบโมโนลิธิกงานเดียวที่ยาว

ในกรณีที่ดีที่สุด ฟังก์ชันเพียงฟังก์ชันเดียวอาจทำให้งานใช้เวลานานขึ้น 50 มิลลิวินาทีหรือมากกว่านั้น ในกรณีที่แย่ที่สุด งานเหล่านี้อาจทำงานได้นานขึ้นมาก โดยเฉพาะในอุปกรณ์ที่มีทรัพยากรจํากัด

เลื่อนเวลาการเรียกใช้โค้ดด้วยตนเอง

วิธีหนึ่งที่นักพัฒนาแอปใช้เพื่อแบ่งงานออกเป็นงานเล็กๆ คือการใช้ setTimeout() เทคนิคนี้ช่วยให้คุณส่งฟังก์ชันไปยัง setTimeout() ได้ ซึ่งจะเลื่อนการดำเนินการของคอลแบ็กไปเป็นงานแยกต่างหาก แม้ว่าคุณจะระบุการหมดเวลาเป็น 0 ก็ตาม

function saveSettings () {
 
// Do critical work that is user-visible:
  validateForm
();
  showSpinner
();
  updateUI
();

 
// Defer work that isn't user-visible to a separate task:
  setTimeout
(() => {
    saveToDatabase
();
    sendAnalytics
();
 
}, 0);
}

การดำเนินการนี้เรียกว่าการให้ผล และเหมาะสําหรับชุดฟังก์ชันที่ต้องทํางานตามลําดับ

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

function processData () {
 
for (const item of largeDataArray) {
   
// Process the individual item here.
 
}
}

การใช้ setTimeout() ในที่นี้ทำให้เกิดปัญหาเนื่องจากความสะดวกสบายของนักพัฒนาซอฟต์แวร์ และอาร์เรย์ข้อมูลทั้งหมดอาจใช้เวลานานมากในการประมวลผล แม้ว่าการวนซ้ำแต่ละครั้งจะทํางานอย่างรวดเร็วก็ตาม ทั้งหมดนี้หมายความว่า setTimeout() ไม่ใช่เครื่องมือที่เหมาะสมสำหรับงานนี้อย่างน้อยก็เมื่อใช้ด้วยวิธีนี้

ใช้ async/await เพื่อสร้างจุดที่มีอัตราผลตอบแทน

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

ตามที่อธิบายไว้ก่อนหน้านี้ setTimeout สามารถใช้เพื่อส่งมอบการควบคุมไปยังเธรดหลัก แต่เพื่อความสะดวกและอ่านง่ายขึ้น คุณสามารถเรียกใช้ setTimeout ภายใน Promise และส่งเมธอด resolve ของ setTimeout เป็นการเรียกกลับได้

function yieldToMain () {
 
return new Promise(resolve => {
    setTimeout
(resolve, 0);
 
});
}

ข้อดีของฟังก์ชัน yieldToMain() คือคุณสามารถawaitฟังก์ชันดังกล่าวในฟังก์ชัน async ใดก็ได้ จากตัวอย่างก่อนหน้านี้ คุณอาจสร้างอาร์เรย์ของฟังก์ชันที่จะเรียกใช้ และส่งคืนไปยังเธรดหลักหลังจากเรียกใช้แต่ละรายการแล้ว ดังนี้

async function saveSettings () {
 
// Create an array of functions to run:
 
const tasks = [
    validateForm
,
    showSpinner
,
    saveToDatabase
,
    updateUI
,
    sendAnalytics
 
]

 
// Loop over the tasks:
 
while (tasks.length > 0) {
   
// Shift the first task off the tasks array:
   
const task = tasks.shift();

   
// Run the task:
    task
();

   
// Yield to the main thread:
    await yieldToMain
();
 
}
}

ผลที่ได้คืองานแบบโมโนลิธิกที่เคยมีตอนนี้แยกออกเป็นงานต่างๆ

ฟังก์ชัน saveSettings เดียวกันกับที่แสดงในเครื่องมือวิเคราะห์ประสิทธิภาพของ Chrome แต่มี Yielding ผลที่ได้คืองานแบบโมโนลิธิกเดิมตอนนี้แยกออกเป็น 5 งานแยกกัน โดยแบ่งเป็น 1 งานสำหรับแต่ละฟังก์ชัน
ตอนนี้ฟังก์ชัน saveSettings() จะเรียกใช้ฟังก์ชันย่อยเป็นงานแยกต่างหาก

Scheduler API โดยเฉพาะ

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

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

การรองรับเบราว์เซอร์

  • Chrome: 94
  • Edge: 94
  • Firefox: อยู่หลังธง
  • Safari: ไม่รองรับ

แหล่งที่มา

Scheduler API มีฟังก์ชัน postTask() ซึ่งช่วยให้ตั้งเวลางานได้ละเอียดยิ่งขึ้น และเป็นวิธีหนึ่งที่ช่วยให้เบราว์เซอร์จัดลําดับความสําคัญของงานเพื่อให้งานที่มีลําดับความสําคัญต่ำทำงานในเธรดหลัก postTask() ใช้ Promise และยอมรับการตั้งค่า priority รูปแบบใดรูปแบบหนึ่งต่อไปนี้

  • 'background' สำหรับงานที่มีลำดับความสำคัญต่ำสุด
  • 'user-visible' สำหรับงานที่มีลำดับความสำคัญปานกลาง การตั้งค่านี้เป็นค่าเริ่มต้นหากไม่ได้ตั้งค่า priority
  • 'user-blocking' สำหรับงานที่สำคัญซึ่งต้องทำงานที่มีลำดับความสำคัญสูง

มาดูตัวอย่างโค้ดต่อไปนี้ที่ใช้ postTask() API เพื่อเรียกใช้งาน 3 รายการที่มีลำดับความสำคัญสูงสุด และงานที่เหลืออีก 2 รายการที่มีลำดับความสำคัญต่ำสุด

function saveSettings () {
 
// Validate the form at high priority
  scheduler
.postTask(validateForm, {priority: 'user-blocking'});

 
// Show the spinner at high priority:
  scheduler
.postTask(showSpinner, {priority: 'user-blocking'});

 
// Update the database in the background:
  scheduler
.postTask(saveToDatabase, {priority: 'background'});

 
// Update the user interface at high priority:
  scheduler
.postTask(updateUI, {priority: 'user-blocking'});

 
// Send analytics data in the background:
  scheduler
.postTask(sendAnalytics, {priority: 'background'});
};

ในส่วนนี้ ระบบจะกำหนดเวลาลำดับความสำคัญของงานในลักษณะที่งานที่มีลำดับความสำคัญสูงกว่าในเบราว์เซอร์ เช่น การโต้ตอบของผู้ใช้ จะได้ทำงานในระหว่างนั้นตามที่จำเป็น

ฟังก์ชัน saveSettings ตามที่แสดงในเครื่องมือวิเคราะห์ประสิทธิภาพของ Chrome แต่ใช้ postTask โดย postTask จะแยกการเรียกใช้ฟังก์ชัน saveSettings แต่ละรายการ และจัดลําดับความสําคัญเพื่อให้การโต้ตอบของผู้ใช้มีโอกาสทํางานโดยไม่ถูกบล็อก
เมื่อเรียกใช้ saveSettings() ฟังก์ชันจะกำหนดเวลาให้กับฟังก์ชันแต่ละรายการโดยใช้ postTask() ระบบจะกำหนดเวลางานที่สำคัญต่อผู้ใช้เป็นลำดับความสำคัญสูง ส่วนงานที่ไม่เกี่ยวข้องกับผู้ใช้จะกำหนดเวลาให้ทำงานในเบื้องหลัง วิธีนี้ช่วยให้การโต้ตอบของผู้ใช้ทํางานได้เร็วขึ้น เนื่องจากมีการแบ่งงานออกเป็นส่วนๆ และจัดลําดับความสําคัญอย่างเหมาะสม

นี่เป็นตัวอย่างง่ายๆ ของการใช้ postTask() คุณสามารถสร้างอินสแตนซ์ออบเจ็กต์ TaskController ที่แตกต่างกันซึ่งสามารถแชร์ลําดับความสําคัญระหว่างงานต่างๆ รวมถึงสามารถเปลี่ยนลําดับความสําคัญสําหรับอินสแตนซ์ TaskController ที่แตกต่างกันได้ตามต้องการ

ผลตอบแทนในตัวที่มีการต่ออายุโดยใช้ scheduler.yield() API

การรองรับเบราว์เซอร์

  • Chrome: 129
  • Edge: 129
  • Firefox: ไม่รองรับ
  • Safari: ไม่รองรับ

แหล่งที่มา

scheduler.yield() เป็น API ที่ออกแบบมาเพื่อส่งมอบชุดข้อความหลักในเบราว์เซอร์โดยเฉพาะ การใช้งานจะคล้ายกับฟังก์ชัน yieldToMain() ที่แสดงก่อนหน้านี้ในคู่มือนี้

async function saveSettings () {
 
// Create an array of functions to run:
 
const tasks = [
    validateForm
,
    showSpinner
,
    saveToDatabase
,
    updateUI
,
    sendAnalytics
 
]

 
// Loop over the tasks:
 
while (tasks.length > 0) {
   
// Shift the first task off the tasks array:
   
const task = tasks.shift();

   
// Run the task:
    task
();

   
// Yield to the main thread with the scheduler
   
// API's own yielding mechanism:
    await scheduler
.yield();
 
}
}

โค้ดนี้คุ้นเคยกันดี แต่จะใช้ await scheduler.yield() แทน yieldToMain()

แผนภาพ 3 แผนภาพแสดงงานที่ไม่มีเงื่อนไขการให้ผล เงื่อนไขการให้ผล และเงื่อนไขการให้ผลและการดําเนินการต่อ หากไม่มีการให้สิทธิ์ใช้งาน อาจมีงานที่ใช้เวลานาน เมื่อใช้ Yield จะมีงานจำนวนมากขึ้นที่ใช้เวลาสั้นลง แต่อาจถูกขัดจังหวะโดยงานอื่นๆ ที่ไม่เกี่ยวข้อง เมื่อใช้ Yielding และ Continuation จะมีงานจำนวนมากขึ้นที่สั้นลง แต่ลำดับการดำเนินการจะยังคงเดิม
เมื่อใช้ scheduler.yield() การดำเนินการของงานจะเริ่มต้นต่อจากจุดที่หยุดไว้แม้ว่าจะผ่านจุดที่มีผลผลิตแล้วก็ตาม

ข้อดีของ scheduler.yield() คือความต่อเนื่อง ซึ่งหมายความว่าหากคุณหยุดกลางคันระหว่างชุดงาน งานอื่นๆ ที่กำหนดเวลาไว้จะยังคงทำงานตามลำดับเดิมหลังจากจุดหยุด วิธีนี้จะช่วยป้องกันไม่ให้โค้ดจากสคริปต์ของบุคคลที่สามขัดจังหวะลําดับการเรียกใช้โค้ด

อย่าใช้ isInputPending()

การรองรับเบราว์เซอร์

  • Chrome: 87
  • Edge: 87
  • Firefox: ไม่รองรับ
  • Safari: ไม่รองรับ

แหล่งที่มา

isInputPending() API มีวิธีตรวจสอบว่าผู้ใช้พยายามโต้ตอบกับหน้าเว็บหรือไม่ และจะแสดงผลก็ต่อเมื่อมีอินพุตที่รอดำเนินการ

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

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

  • isInputPending() อาจแสดงผล false อย่างไม่ถูกต้องแม้ว่าผู้ใช้จะโต้ตอบในบางสถานการณ์ก็ตาม
  • อินพุตไม่ใช่กรณีเดียวที่งานควรให้ผล ภาพเคลื่อนไหวและการอัปเดตอินเทอร์เฟซผู้ใช้ทั่วไปอื่นๆ มีความสำคัญไม่แพ้กับการสร้างหน้าเว็บที่ปรับเปลี่ยนตามอุปกรณ์
  • เราได้เปิดตัว API ที่ให้ผลลัพธ์ที่ครอบคลุมมากขึ้นซึ่งช่วยคลายข้อกังวลเกี่ยวกับผลลัพธ์ เช่น scheduler.postTask() และ scheduler.yield()

บทสรุป

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

  • มอบสิทธิ์ให้ชุดข้อความหลักสำหรับงานที่สําคัญซึ่งแสดงต่อผู้ใช้
  • จัดลำดับความสำคัญของงานด้วย postTask()
  • ลองใช้ scheduler.yield()
  • สุดท้าย ทํางานในฟังก์ชันให้น้อยที่สุด

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

ขอขอบคุณเป็นพิเศษ Philip Walton ที่ช่วยตรวจสอบคู่มือนี้ทางเทคนิค

ภาพปกจาก Unsplash โดยได้รับความอนุเคราะห์จาก Amirali Mirhashemian