เจาะลึกเว็บเบราว์เซอร์สมัยใหม่ (ตอนที่ 4)

Mariko Kosaka

อินพุตกำลังมายังคอมโพสิต

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

ป้อนเหตุการณ์จากมุมมองของเบราว์เซอร์

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

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

วันที่ เหตุการณ์อินพุต
รูปที่ 1: เหตุการณ์อินพุตที่กำหนดเส้นทางผ่านกระบวนการของเบราว์เซอร์ไปยังกระบวนการแสดงผล

คอมโพสิเตอร์รับเหตุการณ์อินพุต

รูปที่ 2: วิวพอร์ตที่วางอยู่เหนือเลเยอร์ของหน้า

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

การทำความเข้าใจภูมิภาคที่เลื่อนได้ที่ไม่เร็ว

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

วันที่ ภูมิภาคที่เลื่อนได้แบบจำกัดและเลื่อนไม่ได้
รูปที่ 3: แผนภาพของข้อมูลที่ระบุสำหรับขอบเขตที่เลื่อนได้ที่ไม่เร็ว

ระมัดระวังเมื่อเขียนเครื่องจัดการเหตุการณ์

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

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

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

วันที่ ภูมิภาคที่เลื่อนได้แบบเต็มหน้า
รูปที่ 4: แผนภาพของข้อมูลที่อธิบายไว้สำหรับพื้นที่ที่เลื่อนได้ไม่เร็วซึ่งครอบคลุมทั้งหน้า

โปรดส่ง passive: true ตัวเลือกในกิจกรรมเพื่อลดปัญหานี้ Listener คําแนะนํานี้สําหรับเบราว์เซอร์ที่คุณยังต้องการฟังเหตุการณ์ในชุดข้อความหลัก แต่เครื่องมือทำ Compose จะสามารถทำการรวมเฟรมใหม่ได้เช่นกัน

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

ตรวจสอบว่ากิจกรรมยกเลิกได้หรือไม่

วันที่ การเลื่อนหน้า
รูปที่ 5: หน้าเว็บที่มีบางส่วนของหน้าเว็บตายตัวตามการเลื่อนแนวนอน

ลองนึกภาพว่าคุณมีช่องในหน้าที่ต้องการจำกัดทิศทางการเลื่อนเป็นการเลื่อนในแนวนอนเท่านั้น

การใช้ตัวเลือก 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
รูปที่ 6: ชุดข้อความหลักที่ดูระเบียน Paint ถามว่าอะไรวาดบนจุด x.y

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

การลดการส่งเหตุการณ์ไปยังเทรดหลัก

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

หากมีการส่งเหตุการณ์ต่อเนื่อง เช่น touchmove ไปยังเทรดหลัก 120 ครั้งต่อวินาที อาจทริกเกอร์การทดสอบ Hit และการเรียกใช้ JavaScript มากเกินไปเมื่อเทียบกับความช้า หน้าจอก็รีเฟรชได้

วันที่ เหตุการณ์ที่ไม่กรอง
รูปที่ 7: เหตุการณ์ที่ทำให้ไทม์ไลน์เฟรมแสดงผลมากเกินไปซึ่งทำให้เกิดการกระตุกของหน้าเว็บ

ในการลดการเรียกไปยังเทรดหลักมากเกินไป Chrome จะรวมเหตุการณ์ต่อเนื่อง (เช่น wheel, mousewheel, mousemove, pointermove, touchmove ) และล่าช้าการจัดส่งไปจนถึง ก่อนถึงrequestAnimationFrameถัดไป

วันที่ เหตุการณ์แบบรวม
รูปที่ 8: ไทม์ไลน์เหมือนเดิม แต่กิจกรรมรวมกันและล่าช้า

เหตุการณ์ที่ไม่ต่อเนื่อง เช่น keydown, keyup, mouseup, mousedown, touchstart และ touchend จะมีการจัดส่งทันที

ใช้ getCoalescedEvents เพื่อรับเหตุการณ์ภายในเฟรม

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

วันที่ getCoalescedEvents
รูปที่ 9: เส้นทางโดยใช้ท่าทางสัมผัสแบบเรียบทางด้านซ้ายซึ่งรวมเส้นทางแบบจำกัดทางด้านขวา
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 DevTools มีบทแนะนำเกี่ยวกับ วิธีวัดประสิทธิภาพของเว็บไซต์

เพิ่มนโยบายฟีเจอร์ในเว็บไซต์ของคุณ

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

สรุป

ขอบคุณ

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

ขอขอบคุณเป็นอย่างสูงสำหรับทุกคนที่ตรวจสอบฉบับร่างช่วงแรกของชุดหนังสือนี้ ซึ่งรวมถึง (แต่ไม่จำกัดเพียง) ถึง): Alex Russell Paul Ireland Meggin Kearney Eric Bidelman Mathias Bynens Addy Osmani Kinuko Yasuda Nasko Oskov และ Charlie Reis

คุณชอบซีรีส์นี้ไหม หากคุณมีคำถามหรือคำแนะนำสำหรับโพสต์ในอนาคต ฉันอยากฟังความเห็นจากคุณในส่วนความคิดเห็นด้านล่างหรือ @kosamari ใน Twitter