เหตุการณ์การป้อนข้อมูลแนวเดียวกัน

เดฟ ตาปูสกา
Dave Tapuska

สรุปคร่าวๆ

  • Chrome 60 ลดความติดขัดด้วยการลดความถี่ของเหตุการณ์ เพื่อปรับปรุงความสม่ำเสมอของเวลาเฟรม
  • เมธอด getCoalescedEvents() ที่เปิดตัวใน Chrome 58 ให้ข้อมูลเหตุการณ์มากมายแบบเดียวกับที่คุณมีมาตลอด

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

เพื่อการใช้งานที่ราบรื่นและประสิทธิภาพ ใน Chrome 60 เรากำลังทำการเปลี่ยนแปลงที่ทำให้เหตุการณ์เหล่านี้เกิดขึ้นในความถี่ที่น้อยลงพร้อมกับเพิ่มรายละเอียดของข้อมูลที่มอบให้ เราจะนำการป้อนข้อมูลที่จัดแนวเฟรมมาแสดงในเว็บในทุกแพลตฟอร์ม ซึ่งคล้ายกับเวลาที่เผยแพร่ Jelly Bean และนำเสนอนักออกแบบท่าเต้นซึ่งจัดเรียงอินพุตใน Android

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

มาพูดถึงความถี่ของเหตุการณ์กันก่อน

ลดความถี่ของเหตุการณ์

เรามาทำความเข้าใจพื้นฐานกันก่อน เช่น หน้าจอสัมผัสจะส่งอินพุตที่อัตรา 60-120 Hz และเมาส์จะส่งอินพุตที่ความถี่ 100 Hz (แต่อาจมีไม่เกิน 2000 Hz) แต่อัตราการรีเฟรชปกติของจอภาพยังอยู่ที่ 60 Hz แล้วนั่นหมายความว่าอย่างไร ซึ่งหมายความว่าเราได้รับอินพุตในอัตราที่สูงกว่าการอัปเดตการแสดงผลจริงๆ เรามาดูไทม์ไลน์ประสิทธิภาพจาก Devtools สำหรับแอปจิตรกรรมผ้าใบแบบง่ายๆ กัน

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

ไทม์ไลน์ประสิทธิภาพแสดงเวลาเฟรมที่ไม่สอดคล้องกัน

แล้วทำไมเราจึงทำงานเพิ่มเติมซึ่งไม่ทำให้เกิดการอัปเดตภาพ ตามหลักแล้ว เราไม่ต้องการทำงานใดๆ ที่ไม่เกิดประโยชน์ต่อผู้ใช้ เริ่มตั้งแต่ Chrome 60 ไปป์ไลน์อินพุตจะหน่วงเวลาการส่งเหตุการณ์ต่อเนื่อง (wheel, mousewheel, touchmove, pointermove, mousemove) และ แจกจ่ายเหตุการณ์เหล่านี้ก่อนที่ requestAnimationFrame() การเรียกกลับ ในภาพด้านล่าง (เมื่อเปิดใช้ฟีเจอร์) คุณจะเห็นเวลาที่ใช้ในการแสดงผลเฟรมที่สม่ำเสมอขึ้นและเหตุการณ์การประมวลผลที่น้อยลง

เราได้ทำการทดสอบด้วยฟีเจอร์นี้ที่เปิดใช้ใน Canary และเวอร์ชันที่กำลังพัฒนา และพบว่าทำการทดสอบ Hit น้อยลง 35% ซึ่งทำให้เทรดหลักพร้อมทำงานบ่อยขึ้น

หมายเหตุสำคัญที่นักพัฒนาเว็บควรทราบคือ เหตุการณ์ใดๆ ก็ตามที่ไม่ต่อเนื่อง (เช่น keydown, keyup, mouseup, mousedown, touchstart, touchend) ที่เกิดขึ้นจะถูกส่งไปพร้อมกับเหตุการณ์ที่รอดำเนินการทั้งหมด โดยคงคำสั่งซื้อที่เกี่ยวข้องไว้ เมื่อเปิดใช้ฟีเจอร์นี้ งานจำนวนมากจะได้รับการปรับให้เป็นโฟลว์ของ event Loop ปกติ ทำให้มีช่วงเวลาในการป้อนข้อมูลที่สม่ำเสมอ การดำเนินการนี้จะแสดงเหตุการณ์ต่อเนื่องในบรรทัดกับเหตุการณ์ scroll และ resize ที่ได้รับการปรับปรุงให้มีประสิทธิภาพมากขึ้นในกระบวนการวนซ้ำเหตุการณ์ใน Chrome แล้ว

ไทม์ไลน์ประสิทธิภาพแสดงเวลาที่ใช้ในการแสดงผลเฟรมที่ค่อนข้างสม่ำเสมอ

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

เมธอด getCoalescedEvents()

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

การเปรียบเทียบเหตุการณ์มาตรฐานกับเหตุการณ์ที่สอดคล้องกัน

คุณสามารถดูอาร์เรย์ของเหตุการณ์ที่ผ่านมาที่ทำให้เกิดเหตุการณ์แทนการรับเหตุการณ์เดียวได้ Android, iOS และ Windows ทั้งหมดมี API ที่คล้ายกันมากใน SDK แบบเนทีฟ และเรากำลังจะเปิดตัว API ที่คล้ายกันในเว็บ

ตามปกติแอปวาดภาพอาจวาดจุดด้วยการดูการชดเชยในเหตุการณ์ โดยทำดังนี้

window.addEventListener("pointermove", function(event) {
    drawPoint(event.pageX, event.pageY);
});

คุณจะเปลี่ยนโค้ดนี้เพื่อใช้อาร์เรย์ของเหตุการณ์ได้ง่ายๆ ดังนี้

window.addEventListener("pointermove", function(event) {
    var events = 'getCoalescedEvents' in event ? event.getCoalescedEvents() : [event];
    for (let e of events) {
    drawPoint(e.pageX, e.pageY);
    }
});

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