การกำหนดเวลา JS ที่ดีขึ้นด้วย isInputPending()

JavaScript API ใหม่ที่อาจช่วยคุณหลีกเลี่ยงการทดแทนระหว่างประสิทธิภาพการโหลดกับการตอบสนองของอินพุต

Nate Schloss
Nate Schloss
Andrew Comminos
Andrew Comminos

การโหลดเร็วเป็นเรื่องยาก เว็บไซต์ที่ใช้ประโยชน์จาก JS เพื่อแสดงเนื้อหาในปัจจุบัน เราต้องทดแทนกันระหว่างประสิทธิภาพการโหลดและอินพุต การตอบสนอง: ทำงานทั้งหมดที่จำเป็นสำหรับการแสดงผล พร้อมกันทั้งหมด (ประสิทธิภาพการโหลดที่ดีขึ้น การตอบสนองของอินพุตที่แย่ลง) หรือ แบ่งงานออกเป็นงานย่อยๆ เพื่อให้ยังคงตอบสนองต่อ อินพุตและการแสดงผล (ประสิทธิภาพการโหลดต่ำ, อินพุตที่ดีกว่า การตอบสนอง)

เพื่อขจัดความจำเป็นในการตัดสิทธิ์นี้ Facebook จึงเสนอและนำมาใช้ isInputPending() API ใน Chromium เพื่อปรับปรุงการตอบสนองโดยไม่ต้อง ผลตอบแทน จากความคิดเห็นเกี่ยวกับช่วงทดลองใช้จากต้นทาง เราได้ทำการอัปเดต API และยินดีที่จะประกาศว่าขณะนี้ API จัดส่งใน Chromium เป็นค่าเริ่มต้นแล้ว 87!

ความเข้ากันได้กับเบราว์เซอร์

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

  • Chrome: 87.
  • ขอบ: 87
  • Firefox: ไม่สนับสนุน
  • Safari: ไม่รองรับ

แหล่งที่มา

isInputPending() จัดส่งในเบราว์เซอร์แบบ Chromium ตั้งแต่เวอร์ชัน 87 เป็นต้นไป ไม่มีเบราว์เซอร์อื่นส่งสัญญาณความตั้งใจที่จะจัดส่ง API

ข้อมูลเบื้องต้น

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

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

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

แผนภาพที่แสดงให้เห็นว่าเมื่อคุณทำงาน JS ที่ใช้เวลานาน เบราว์เซอร์จะมีเวลาในการส่งกิจกรรมน้อยลง

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

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

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

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

ตัวอย่าง: เครื่องจัดตารางเวลา Yieldier

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

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (performance.now() >= DEADLINE) {
    // Yield the event loop if we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

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

ไม่เป็นไร แต่จะปรับปรุงให้ดีขึ้นได้ไหม แน่นอน!

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending() || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event, or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

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

โดยค่าเริ่มต้นคือ "ต่อเนื่อง" ไม่มีการส่งคืนกิจกรรมจาก isInputPending() เหล่านี้ รวม mousemove, pointermove และอื่นๆ หากคุณสนใจให้ผลตอบแทนสำหรับ เรื่องพวกนี้ก็เช่นกัน โดยการระบุออบเจ็กต์แก่ isInputPending() ด้วย ตั้งค่า includeContinuous เป็น true พร้อมใช้งานแล้ว:

const DEADLINE = performance.now() + QUANTUM;
const options = { includeContinuous: true };
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending(options) || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event (any of them!), or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

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

ผลตอบแทนไม่ได้แย่เสมอไป

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

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

โปรดระวังหน้าอื่นๆ ที่แชร์ลูปเหตุการณ์ด้วย ในแพลตฟอร์มต่างๆ เช่น Chrome สำหรับ Android เป็นเรื่องปกติที่ต้นทางหลายแห่งจะแชร์เหตุการณ์ วนซ้ำ isInputPending() จะไม่แสดงผล true หากมีการส่งอินพุตไปยัง เฟรมแบบข้ามต้นทาง หน้าที่อยู่ในเบื้องหลังอาจรบกวน การตอบสนองของหน้าเบื้องหน้า คุณอาจต้องการลด ขยับ หรือ บ่อยขึ้นเมื่อทำงานอยู่เบื้องหลังโดยใช้ Page Monetization API

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

ความคิดเห็น

  • โปรดแสดงความคิดเห็นเกี่ยวกับข้อมูลจำเพาะใน is-input-pending
  • ติดต่อ @acomminos (หนึ่งในผู้เขียนข้อกำหนด) ใน Twitter

บทสรุป

เราตื่นเต้นที่ isInputPending() กำลังจะเปิดตัว และนักพัฒนาซอฟต์แวร์สามารถ เพื่อเริ่มใช้งานวันนี้เลย API นี้เป็นครั้งแรกที่ Facebook ได้สร้าง เว็บ API ใหม่ และนำมาจากการบ่มเพาะความคิด ไปสู่การนำเสนอมาตรฐานเพื่อ การจัดส่งในเบราว์เซอร์ เราต้องขอขอบคุณทุกคนที่ช่วยเราทำสิ่งนี้ และกล่าวขอบคุณทุกคนที่ Chrome ซึ่งช่วยเราได้ ไอเดียนี้ แล้วจัดส่งไปให้!

รูปภาพหลักโดย Will H McMahan ใน หน้าจอแนะนํา