กำลังป้อนอินพุตไปยังตัวองค์ประกอบ
นี่เป็นตอนสุดท้ายของบล็อก 4 ตอนใน Chrome มาลองดูกันว่าจะมีการจัดการโค้ดเพื่อแสดงเว็บไซต์อย่างไร ในโพสต์ก่อนหน้านี้ เราได้พูดถึงกระบวนการแสดงผลและได้เรียนรู้เกี่ยวกับตัวจัดวางองค์ประกอบ ในโพสต์นี้ เราจะดูว่า ตัวประกอบทำให้การโต้ตอบราบรื่นเมื่อผู้ใช้ป้อนข้อมูลเข้ามาได้อย่างไร
ป้อนเหตุการณ์จากมุมมองของเบราว์เซอร์
เมื่อคุณได้ยิน "เหตุการณ์การป้อนข้อมูล" คุณอาจนึกถึงการพิมพ์ในช่องข้อความหรือการคลิกเมาส์เท่านั้น แต่จากมุมมองของเบราว์เซอร์ การป้อนข้อมูลหมายถึงท่าทางสัมผัสของผู้ใช้ การเลื่อนด้วยล้อเลื่อนของเมาส์เป็นเหตุการณ์อินพุต และการแตะหรือเมาส์เหนือก็เป็นเหตุการณ์อินพุตเช่นกัน
เมื่อมีการใช้ท่าทางสัมผัสของผู้ใช้ เช่น การแตะหน้าจอ เบราว์เซอร์จะรับท่าทางสัมผัสในตอนแรก อย่างไรก็ตาม กระบวนการของเบราว์เซอร์จะทราบเฉพาะเมื่อท่าทางสัมผัสดังกล่าวเกิดขึ้นเนื่องจากเนื้อหาภายในแท็บได้รับการจัดการโดยกระบวนการแสดงผล ดังนั้นกระบวนการของเบราว์เซอร์จะส่งประเภทเหตุการณ์ (เช่น touchstart
) และพิกัดของเหตุการณ์ไปยังกระบวนการแสดงผล กระบวนการแสดงผลจะจัดการเหตุการณ์อย่างเหมาะสมโดยค้นหาเป้าหมายเหตุการณ์และ Listener เหตุการณ์ที่ทำงานอยู่ที่แนบมา
![เหตุการณ์อินพุต](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/input-event-265a73164e715.png?authuser=1&hl=th)
คอมโพสิตได้รับเหตุการณ์อินพุต
ในโพสต์ก่อนหน้านี้ เราดูว่าตัวทำองค์ประกอบสามารถจัดการการเลื่อนอย่างราบรื่นโดยการประกอบเลเยอร์แบบแรสเตอร์ได้อย่างไร หากไม่ได้แนบ Listener เหตุการณ์อินพุตกับหน้าเว็บ เทรดคอมโพสิตจะสร้างเฟรมผสมใหม่เลยก็ได้โดยไม่เกี่ยวข้องกับเทรดหลัก แต่จะเกิดอะไรขึ้นหากมีผู้ฟัง เหตุการณ์บางเหตุการณ์แนบอยู่กับหน้า เทรดคอมโพสิเตอร์จะทราบได้อย่างไรว่าต้องจัดการเหตุการณ์หรือไม่
ทำความเข้าใจภูมิภาคแบบเลื่อนได้ที่ไม่เร็ว
เนื่องจากการเรียกใช้ JavaScript เป็นงานของเทรดหลัก เมื่อหน้าทำการ Composite เทรดคอมโพสิเตอร์จะทำเครื่องหมายภูมิภาคของหน้าที่มีตัวแฮนเดิลเหตุการณ์แนบเป็น "ภูมิภาคแบบเลื่อนได้แบบไม่เร็ว" เมื่อมีข้อมูลนี้ เทรดคอมโพสเซอร์จะสามารถส่งเหตุการณ์อินพุตไปยังเทรดหลักได้หากมีเหตุการณ์เกิดขึ้นในภูมิภาคนั้น หากเหตุการณ์อินพุตมาจากนอกภูมิภาคนี้ เทรดของตัวคอมโพเนนต์จะทำงานในการจัดเฟรมใหม่โดยไม่ต้องรอเทรดหลัก
![ภูมิภาคที่เลื่อนได้ไม่เร็วแบบจำกัด](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/limited-non-fast-scrollab-376be5ee2cd6b.png?authuser=1&hl=th)
ระมัดระวังเมื่อคุณเขียนเครื่องจัดการเหตุการณ์
รูปแบบการจัดการเหตุการณ์ที่พบบ่อยในการพัฒนาเว็บคือการมอบสิทธิ์เหตุการณ์ เนื่องจากลูกโป่งกิจกรรม คุณจึงแนบเครื่องจัดการเหตุการณ์ 1 รายการที่องค์ประกอบด้านบนสุดและมอบสิทธิ์งานตามเป้าหมายเหตุการณ์ได้ คุณอาจเคยเห็นหรือเขียนโค้ดดังตัวอย่างต่อไปนี้
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault();
}
});
เนื่องจากคุณต้องเขียนเครื่องจัดการเหตุการณ์เพียงรายการเดียวสำหรับทุกองค์ประกอบ รูปแบบการมอบสิทธิ์ของกิจกรรมนี้จึงดูน่าสนใจ อย่างไรก็ตาม หากคุณดูโค้ดนี้จากมุมมองของเบราว์เซอร์ ตอนนี้ทั้งหน้าจะมีการทำเครื่องหมายเป็นภูมิภาคที่เลื่อนได้แบบรวดเร็ว ซึ่งหมายความว่าแม้ว่าแอปพลิเคชันจะไม่สนใจอินพุตจากบางส่วนของหน้าเว็บ แต่เทรดคอมโพสิเตอร์จะต้องสื่อสารกับเทรดหลักและรอคอยทุกครั้งที่เหตุการณ์อินพุตเข้ามา ดังนั้น ความสามารถในการเลื่อนอย่างราบรื่นของเครื่องประกอบหน้าเว็บจึงแพ้
![ภูมิภาคที่เลื่อนได้ไม่เร็วทั้งหน้า](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/full-page-non-fast-scroll-dd3010cc3ee0f.png?authuser=1&hl=th)
คุณสามารถส่งตัวเลือก passive: true
ในตัวฟังเหตุการณ์เพื่อลดปัญหานี้ คำแนะนำนี้สำหรับเบราว์เซอร์ที่คุณยังคงต้องการฟังเหตุการณ์ในเทรดหลัก
แต่เครื่องมือทำองค์ประกอบก็สามารถใส่เฟรมใหม่ได้เลย
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
ตรวจสอบว่ากิจกรรมยกเลิกได้หรือไม่
![การเลื่อนหน้า](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/page-scroll-2cf8d804f8587.png?authuser=1&hl=th)
ลองนึกภาพว่าคุณมีช่องในหน้าที่ต้องการจำกัดทิศทางการเลื่อนให้เป็นการเลื่อนในแนวนอนเท่านั้น
การใช้ตัวเลือก passive: true
ในเหตุการณ์ตัวชี้จะทำให้การเลื่อนหน้าเว็บเป็นไปอย่างราบรื่น แต่การเลื่อนแนวตั้งอาจเริ่มจากเวลาที่คุณต้องการpreventDefault
เพื่อจำกัดทิศทางการเลื่อน คุณตรวจสอบปัญหานี้ได้โดยใช้เมธอด event.cancelable
document.body.addEventListener('pointermove', event => {
if (event.cancelable) {
event.preventDefault(); // block the native scroll
/*
* do what you want the application to do here
*/
}
}, {passive: true});
หรือคุณอาจใช้กฎ CSS เช่น touch-action
เพื่อกำจัดเครื่องจัดการเหตุการณ์โดยสมบูรณ์
#area {
touch-action: pan-x;
}
หาเป้าหมายของเหตุการณ์
![การทดสอบ Hit](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/hit-test-39f1d20855064.png?authuser=1&hl=th)
เมื่อเทรดคอมโพสิเตอร์ส่งเหตุการณ์อินพุตไปยังเทรดหลัก สิ่งแรกที่ต้องเรียกใช้คือการทดสอบ Hit เพื่อค้นหาเป้าหมายเหตุการณ์ การทดสอบ Hit ใช้ข้อมูลระเบียนสีที่สร้างขึ้นในกระบวนการแสดงผลเพื่อค้นหาสิ่งที่อยู่ใต้พิกัดจุดซึ่งเหตุการณ์เกิดขึ้น
การลดการส่งเหตุการณ์ไปยังเทรดหลัก
ในโพสต์ก่อนหน้านี้ เราพูดถึงวิธีที่จอแสดงผลทั่วไปรีเฟรชหน้าจอ 60 ครั้งต่อวินาที และดูว่าเราต้องตามจังหวะเพื่อให้ภาพเคลื่อนไหวลื่นไหลได้อย่างไร สำหรับการป้อนข้อมูล อุปกรณ์หน้าจอสัมผัสทั่วไปจะส่งเหตุการณ์การแตะที่ 60-120 ครั้งต่อวินาที และเมาส์ทั่วไปจะส่งเหตุการณ์ 100 ครั้งต่อวินาที เหตุการณ์อินพุตมีความแม่นยำสูงกว่าหน้าจอที่รีเฟรชได้
หากมีการส่งเหตุการณ์ต่อเนื่อง เช่น touchmove
ไปยังเทรดหลัก 120 ครั้งต่อวินาที ก็อาจทำให้มีการทดสอบ Hit และการดำเนินการ JavaScript มากเกินไปเมื่อเทียบกับความช้าของการรีเฟรชหน้าจอ
![กิจกรรมที่ไม่กรอง](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/unfiltered-events-5c569da8f6466.png?authuser=1&hl=th)
Chrome จะจัดกลุ่มเหตุการณ์ต่อเนื่อง (เช่น wheel
, mousewheel
, mousemove
, pointermove
, touchmove
) และหน่วงเวลาการส่งโฆษณาจนถึง requestAnimationFrame
ถัดไป เพื่อลดการเรียกใช้เทรดหลักมากเกินไป
![กิจกรรมที่รวมเป็นชุด](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/coalesced-events-42fbb3813612d.png?authuser=1&hl=th)
ระบบจะส่งเหตุการณ์แยกต่างหากทั้งหมด เช่น keydown
, keyup
, mouseup
, mousedown
, touchstart
และ touchend
ทันที
ใช้ getCoalescedEvents
เพื่อรับเหตุการณ์ภายในเฟรม
สำหรับเว็บแอปพลิเคชันส่วนใหญ่ กิจกรรมที่เป็นเส้นประสานก็น่าจะเพียงพอแล้วให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดี
อย่างไรก็ตาม ถ้าคุณกำลังสร้างสิ่งต่างๆ เช่น แอปพลิเคชันการวาดภาพและวางเส้นทางตามพิกัด touchmove
คุณอาจสูญเสียระหว่างพิกัดในการวาดเส้นเรียบ ในกรณีดังกล่าว คุณสามารถใช้เมธอด getCoalescedEvents
ในเหตุการณ์ตัวชี้เพื่อดูข้อมูลเกี่ยวกับเหตุการณ์ที่รวมเข้าด้วยกันเหล่านั้น
![getCoalescedEvents](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/getcoalescedevents-ab59c1cb92e1b.png?authuser=1&hl=th)
window.addEventListener('pointermove', event => {
const events = event.getCoalescedEvents();
for (let event of events) {
const x = event.pageX;
const y = event.pageY;
// draw a line using x and y coordinates.
}
});
ขั้นตอนถัดไป
ในซีรีส์นี้ เราได้พูดถึงการทำงานภายในของเว็บเบราว์เซอร์ หากคุณไม่เคยนึกถึงเหตุผลที่
เครื่องมือสำหรับนักพัฒนาเว็บแนะนำให้เพิ่ม {passive: true}
ในเครื่องจัดการเหตุการณ์ หรือเหตุผลที่คุณอาจเขียนแอตทริบิวต์ async
ในแท็กสคริปต์ เราหวังว่าซีรีส์นี้จะอธิบายเหตุผลที่เบราว์เซอร์ต้องใช้ข้อมูลเหล่านั้นเพื่อมอบประสบการณ์การใช้งานเว็บที่รวดเร็วและลื่นไหลยิ่งขึ้น
ใช้ Lighthouse
หากคุณต้องการให้โค้ดเหมาะกับเบราว์เซอร์ แต่ไม่รู้ว่าต้องเริ่มต้นตรงไหน Lighthouse คือเครื่องมือที่ให้บริการตรวจสอบเว็บไซต์ต่างๆ และมอบรายงานให้คุณทราบถึงสิ่งที่ดำเนินการได้อย่างถูกต้องและสิ่งที่ควรปรับปรุง นอกจากนี้ การอ่านรายการการตรวจสอบยังช่วยให้คุณเห็นภาพของสิ่งที่เบราว์เซอร์ให้ความสำคัญ
ดูวิธีวัดประสิทธิภาพ
การปรับเปลี่ยนประสิทธิภาพอาจแตกต่างกันไปตามเว็บไซต์ต่างๆ จึงจำเป็นที่คุณจะต้องวัดประสิทธิภาพของเว็บไซต์และตัดสินใจว่าสิ่งใดเหมาะกับเว็บไซต์ของคุณที่สุด ทีมเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome มีบทแนะนำเกี่ยวกับ วิธีวัดประสิทธิภาพเว็บไซต์
เพิ่มนโยบายฟีเจอร์ลงในเว็บไซต์
หากคุณต้องการดำเนินการเพิ่มเติมอีกขั้น นโยบายฟีเจอร์คือฟีเจอร์ใหม่ของแพลตฟอร์มบนเว็บที่อาจเป็นแนวทางให้คุณเมื่อสร้างโปรเจ็กต์ การเปิดนโยบายฟีเจอร์รับประกันลักษณะการทำงานบางอย่างของแอปและป้องกันไม่ให้คุณทำงานผิดพลาด
ตัวอย่างเช่น หากต้องการดูแลไม่ให้แอปบล็อกการแยกวิเคราะห์ ให้เรียกใช้แอปตามนโยบายสคริปต์แบบซิงโครนัส เมื่อเปิดใช้ sync-script: 'none'
ระบบจะป้องกันไม่ให้ JavaScript ที่บล็อกโปรแกรมแยกวิเคราะห์ทำงาน ซึ่งจะป้องกันไม่ให้โค้ดของคุณบล็อกโปรแกรมแยกวิเคราะห์ และเบราว์เซอร์ก็ไม่ต้องกังวลเรื่องการหยุดโปรแกรมแยกวิเคราะห์ชั่วคราว
สรุป
![ขอบคุณ](https://developer.chrome.google.cn/static/blog/inside-browser-part4/image/thank-you-cae9a20f3c237.png?authuser=1&hl=th)
ตอนที่ผมเริ่มสร้างเว็บไซต์ ผมแทบสนใจเฉพาะวิธีเขียนโค้ดและสิ่งที่จะช่วยให้ ผมทำงานได้อย่างมีประสิทธิภาพมากขึ้น เรื่องนี้มีความสำคัญมาก แต่เราก็ควรคำนึงถึงวิธีที่เบราว์เซอร์ นำโค้ดที่เราเขียนไปใช้ด้วย เบราว์เซอร์ที่ทันสมัยได้มีการลงทุนอย่างต่อเนื่องเพื่อช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานเว็บที่ดีขึ้น การจัดระเบียบโค้ดของเราอย่างสุภาพต่อเบราว์เซอร์ นำไปสู่การปรับปรุงประสบการณ์ของผู้ใช้ หวังว่าคุณจะร่วมทำภารกิจพิชิตใจเบราว์เซอร์ของเรา
ขอขอบคุณทุกคนที่รีวิวเนื้อหาฉบับร่างช่วงแรกๆ ของซีรีส์นี้ ซึ่งรวมถึง (แต่ไม่จำกัดเพียง Alex Russell, Paul Ireland, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasaskie, Kinuko Yasaskie
คุณชอบซีรีส์นี้ไหม หากคุณมีคำถามหรือคำแนะนำสำหรับโพสต์ในอนาคต เรายินดีรับฟังความคิดเห็นจากคุณในส่วนความคิดเห็นด้านล่างหรือ @kosamari บน Twitter