อย่าต่อสู้กับตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์

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

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

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

เครื่องมือสแกนเพื่อโหลดล่วงหน้าคืออะไร

เบราว์เซอร์ทุกตัวมีโปรแกรมแยกวิเคราะห์ HTML หลักที่แยกคำมาร์กอัปดิบ และประมวลผลเป็นโมเดลออบเจ็กต์ การดำเนินการทั้งหมดนี้ดำเนินไปอย่างราบรื่นจนกว่าโปรแกรมแยกวิเคราะห์จะหยุดชั่วคราวเมื่อพบทรัพยากรที่บล็อก เช่น สไตล์ชีตที่โหลดด้วยองค์ประกอบ <link> หรือสคริปต์ที่โหลดด้วยองค์ประกอบ <script> ที่ไม่มีแอตทริบิวต์ async หรือ defer

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

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

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

นอกจากนี้เบราว์เซอร์ยังบล็อกการแยกวิเคราะห์และการแสดงผลหน้าเว็บเมื่อพบองค์ประกอบ <script> ที่ไม่มีแอตทริบิวต์ defer หรือ async ด้วย

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

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

แผนภาพทั้งของโปรแกรมแยกวิเคราะห์ HTML หลัก (ซ้าย) และเครื่องมือสแกนเพื่อโหลดล่วงหน้า (ขวา) ซึ่งเป็นโปรแกรมแยกวิเคราะห์ HTML รอง
รูปที่ 3: แผนภาพที่แสดงวิธีที่เครื่องมือสแกนเพื่อโหลดล่วงหน้าทํางานควบคู่กับโปรแกรมแยกวิเคราะห์ HTML หลักเพื่อโหลดชิ้นงานโดยประมาณ ในกรณีนี้ ตัวแยกวิเคราะห์ HTML หลักจะถูกบล็อกขณะที่โหลดและประมวลผล CSS ก่อนที่จะเริ่มประมวลผลมาร์กอัปรูปภาพในองค์ประกอบ <body> แต่เครื่องมือสแกนเพื่อโหลดล่วงหน้าจะมองไปข้างหน้าในมาร์กอัปดิบเพื่อค้นหาแหล่งข้อมูลรูปภาพนั้นและเริ่มโหลดก่อนที่จะเลิกบล็อกตัวแยกวิเคราะห์ HTML หลัก

บทบาทของสแกนเนอร์การโหลดล่วงหน้าคือการคาดเดา ซึ่งหมายความว่าจะตรวจสอบมาร์กอัปดิบเพื่อค้นหาทรัพยากรที่จะดึงข้อมูลเมื่อมีโอกาสก่อนที่โปรแกรมแยกวิเคราะห์ HTML หลักจะค้นพบ

วิธีดูว่าเครื่องมือสแกนเพื่อโหลดล่วงหน้าทำงานอยู่หรือไม่

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

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

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

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

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

สคริปต์ async ที่แทรก

สมมติว่าคุณมี HTML ใน <head> ที่มี JavaScript ในบรรทัด เช่น

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

สคริปต์ที่แทรกจะเป็น async โดยค่าเริ่มต้น ดังนั้นเมื่อแทรกสคริปต์นี้ ระบบจะทํางานเหมือนกับว่ามีการใช้แอตทริบิวต์ async กับสคริปต์ ซึ่งหมายความว่าจะทํางานโดยเร็วที่สุดและจะไม่บล็อกการแสดงผล ฟังดูเหมาะเจาะดีใช่ไหม แต่หากคุณคิดว่า <script> ในบรรทัดนี้อยู่หลังองค์ประกอบ <link> ที่โหลดไฟล์ CSS ภายนอก คุณจะได้รับผลลัพธ์ที่ไม่เหมาะสม

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

มาดูรายละเอียดสิ่งที่เกิดขึ้นกัน

  1. เมื่อถึง 0 วินาที ระบบจะขอเอกสารหลัก
  2. เมื่อถึง 1.4 วินาที ไบต์แรกของคำขอการนําทางจะมาถึง
  3. เมื่อถึง 2.0 วินาที ระบบจะขอ CSS และรูปภาพ
  4. เนื่องจากโปรแกรมแยกวิเคราะห์ถูกบล็อกไม่ให้โหลดสไตล์ชีต และ JavaScript แบบอินไลน์ที่แทรกสคริปต์ async มาหลังสไตล์ชีตนั้นที่ 2.6 วินาที ฟังก์ชันการทำงานที่สคริปต์ให้จึงใช้งานไม่ได้เร็วที่สุดเท่าที่ควร

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

จะเกิดอะไรขึ้นหากคุณใช้แท็ก <script> ปกติที่มีแอตทริบิวต์ async แทนที่จะแทรกสคริปต์ลงใน DOM

<script src="/yall.min.js" async></script>

ผลลัพธ์ที่ได้คือ

Waterfall ของเครือข่าย WebPageTest ที่แสดงให้เห็นว่าสคริปต์แบบแอซิงค์ที่โหลดโดยใช้องค์ประกอบสคริปต์ HTML ยังคงค้นพบได้โดยเครื่องมือสแกนการโหลดล่วงหน้าของเบราว์เซอร์ แม้ว่าโปรแกรมแยกวิเคราะห์ HTML หลักของเบราว์เซอร์จะถูกบล็อกขณะดาวน์โหลดและประมวลผลสไตล์ชีต
รูปที่ 6: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง หน้าเว็บมีสไตล์ชีตเดียวและองค์ประกอบ async <script> รายการเดียว ตัวสแกนการโหลดล่วงหน้าจะตรวจหาสคริปต์ในระยะที่บล็อกการแสดงผล และโหลดสคริปต์นั้นพร้อมกับ CSS

คุณอาจอยากแนะนำให้แก้ปัญหาเหล่านี้โดยใช้ rel=preload วิธีนี้ได้ผลแน่นอน แต่อาจมีผลข้างเคียงบางอย่าง ท้ายที่สุดแล้ว เหตุใดจึงต้องใช้ rel=preload เพื่อแก้ไขปัญหาที่หลีกเลี่ยงได้ด้วยการไม่แทรกองค์ประกอบ <script> ลงใน DOM

Waterfall ของ WebPageTest ที่แสดงวิธีใช้คำแนะนำทรัพยากร rel=preload เพื่อโปรโมตการค้นพบสคริปต์ที่แทรกแบบอะซิงโครนัส แม้ว่าจะเป็นวิธีที่อาจทำให้เกิดผลข้างเคียงที่ไม่ตั้งใจก็ตาม
รูปที่ 7: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง หน้าเว็บมีสไตล์ชีตเดียวและสคริปต์ async ที่แทรก แต่ระบบจะโหลดสคริปต์ async ไว้ล่วงหน้าเพื่อให้ระบบค้นพบได้เร็วขึ้น

การป้อนข้อมูลล่วงหน้า "แก้ไข" ปัญหานี้ แต่ทำให้เกิดปัญหาใหม่คือ สคริปต์ async ในเดโม 2 รายการแรกแม้จะโหลดใน <head> ก็ตาม แต่ระบบจะโหลดโดยมีลําดับความสําคัญเป็น "ต่ำ" ส่วนสไตล์ชีตจะโหลดโดยมีลําดับความสําคัญเป็น "สูงสุด" ในเดโมล่าสุดที่โหลดสคริปต์ async ไว้ล่วงหน้า ไฟล์สไตล์จะยังคงโหลดโดยมีลําดับความสําคัญเป็น "สูงสุด" แต่ลําดับความสําคัญของสคริปต์ได้รับการเลื่อนเป็น "สูง"

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

คำตอบนั้นง่ายมาก หากต้องใช้สคริปต์ระหว่างการเริ่มต้น ให้หลีกเลี่ยงการสกัดการสแกนการโหลดล่วงหน้าโดยการแทรกสคริปต์ลงใน DOM ทดสอบตำแหน่งองค์ประกอบ <script> และแอตทริบิวต์ต่างๆ เช่น defer และ async ตามที่จำเป็น

การโหลดเมื่อจำเป็นด้วย JavaScript

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

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

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

การใช้คำนำหน้า data- เป็นรูปแบบที่พบได้ทั่วไปในเครื่องมือโหลดแบบเลื่อนเวลา (Lazy Loader) ที่ทำงานด้วย JavaScript เมื่อเลื่อนรูปภาพไปยังวิวพอร์ต ตัวโหลดแบบเลื่อนช้าจะตัดคำนำหน้า data- ออก ซึ่งหมายความว่าในตัวอย่างก่อนหน้านี้ data-src จะกลายเป็น src การอัปเดตนี้จะแจ้งให้เบราว์เซอร์ดึงข้อมูล

รูปแบบนี้จะไม่มีปัญหาจนกว่าจะใช้กับรูปภาพที่อยู่ในวิวพอร์ตระหว่างการเริ่มต้น เนื่องจากเครื่องมือสแกนการโหลดล่วงหน้าไม่ได้อ่านแอตทริบิวต์ data-src ในลักษณะเดียวกับที่อ่านแอตทริบิวต์ src (หรือ srcset) ระบบจึงไม่พบการอ้างอิงรูปภาพก่อนหน้านี้ ที่แย่กว่านั้นคือรูปภาพจะโหลดล่าช้าจนกว่าจะหลัง JavaScript ของ Lazy Loader ดาวน์โหลด คอมไพล์ และดำเนินการ

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงการหน่วงเวลาของรูปภาพที่โหลดแบบเลื่อนเวลาอยู่ในวิวพอร์ตระหว่างการเริ่มต้น เนื่องจากเครื่องมือสแกนการโหลดล่วงหน้าของเบราว์เซอร์ไม่พบทรัพยากรรูปภาพ และโหลดเฉพาะเมื่อโหลด JavaScript ที่จําเป็นสําหรับการโหลดแบบเลื่อนเวลา ระบบค้นพบรูปภาพช้ากว่าที่ควรจะเป็น
รูปที่ 8: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง ทรัพยากรรูปภาพมีการโหลดแบบ Lazy โดยไม่จำเป็น แม้ว่าจะแสดงในวิวพอร์ตระหว่างการเริ่มต้นใช้งาน ซึ่งจะขัดขวางการสแกนการโหลดล่วงหน้าและทำให้เกิดความล่าช้าที่ไม่จำเป็น

รูปภาพอาจเป็นองค์ประกอบที่เป็นไปได้สำหรับ Largest Contentful Paint (LCP) ทั้งนี้ขึ้นอยู่กับขนาดของรูปภาพ ซึ่งอาจขึ้นอยู่กับขนาดของวิวพอร์ต เมื่อเครื่องมือสแกนการโหลดล่วงหน้าไม่สามารถคาดเดาและดึงข้อมูลทรัพยากรรูปภาพล่วงหน้าได้ ซึ่งอาจเกิดขึ้นเมื่อสไตล์ชีตของหน้าเว็บบล็อกการแสดงผล LCP จะได้รับผลกระทบ

วิธีแก้ปัญหาคือเปลี่ยนมาร์กอัปรูปภาพ โดยทำดังนี้

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

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

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

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

รูปภาพพื้นหลัง CSS

โปรดทราบว่าเครื่องมือสแกนการโหลดล่วงหน้าของเบราว์เซอร์จะสแกนมาร์กอัป แต่จะไม่ได้สแกนทรัพยากรประเภทอื่นๆ เช่น CSS ซึ่งอาจเกี่ยวข้องกับการดึงข้อมูลรูปภาพที่อ้างอิงโดยพร็อพเพอร์ตี้ background-image

เช่นเดียวกับ HTML เบราว์เซอร์จะประมวลผล CSS เป็นโมเดลออบเจ็กต์ของตัวเอง ซึ่งเรียกว่า CSSOM หากพบทรัพยากรภายนอกขณะสร้าง CSSOM ระบบจะขอทรัพยากรเหล่านั้น ณ เวลาที่ค้นพบ ไม่ใช่โดยเครื่องมือสแกนเพื่อโหลดล่วงหน้า

สมมติว่า LCP Candidate ของหน้าเว็บคือองค์ประกอบที่มีพร็อพเพอร์ตี้ background-image ของ CSS สิ่งที่จะเกิดขึ้นเมื่อโหลดทรัพยากรมีดังนี้

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงหน้าเว็บที่มี LCP ที่เป็นไปได้ซึ่งโหลดจาก CSS โดยใช้พร็อพเพอร์ตี้ background-image เนื่องจากรูปภาพผู้สมัคร LCP อยู่ในประเภททรัพยากรที่สแกนเนอร์การโหลดล่วงหน้าของเบราว์เซอร์ไม่สามารถตรวจสอบได้ ทรัพยากรจึงโหลดล่าช้าจนกว่าระบบจะดาวน์โหลดและประมวลผล CSS ซึ่งทำให้เวลาในการแสดงผลของผู้สมัคร LCP ล่าช้า
รูปที่ 10: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง LCP ที่เป็นไปได้ของหน้าคือองค์ประกอบที่มีพร็อพเพอร์ตี้ CSS background-image (แถวที่ 3) รูปภาพที่ขอจะไม่เริ่มดึงข้อมูลจนกว่าโปรแกรมแยกวิเคราะห์ CSS จะพบ

ในกรณีนี้ การสแกนเพื่อโหลดล่วงหน้าไม่ได้ถูกบล็อก แต่ไม่ได้มีส่วนเกี่ยวข้อง อย่างไรก็ตาม หาก LCP ที่เป็นไปได้ในหน้าเว็บมาจากพร็อพเพอร์ตี้ background-image CSS คุณจะต้องโหลดรูปภาพนั้นล่วงหน้า โดยทำดังนี้

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

คำแนะนำ rel=preload นั้นเล็ก แต่ช่วยให้เบราว์เซอร์ค้นพบรูปภาพได้เร็วขึ้น

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงภาพพื้นหลัง CSS (ซึ่งเป็น LCP ที่เป็นไปได้) ที่โหลดเร็วขึ้นมากเนื่องจากการใช้คำแนะนำ rel=preload เวลา LCP ดีขึ้นประมาณ 250 มิลลิวินาที
รูปที่ 11: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง LCP ที่เป็นไปได้ของหน้าคือองค์ประกอบที่มีพร็อพเพอร์ตี้ CSS background-image (แถวที่ 3) คำแนะนำ rel=preload ช่วยให้เบราว์เซอร์ค้นพบรูปภาพได้เร็วขึ้นประมาณ 250 มิลลิวินาทีเมื่อเทียบกับไม่มีคำแนะนำ

การใช้คำแนะนำ rel=preload จะทำให้ระบบค้นพบ LCP ที่เป็นไปได้ได้เร็วขึ้น ซึ่งจะช่วยลดเวลา LCP แม้ว่าคำแนะนำดังกล่าวจะช่วยแก้ไขปัญหานี้ได้ แต่ตัวเลือกที่ดีกว่าอาจเป็นการประเมินว่า LCP ของรูปภาพต้องต้องโหลดจาก CSS หรือไม่ การใช้แท็ก <img> จะช่วยให้คุณควบคุมการโหลดรูปภาพที่เหมาะกับวิวพอร์ตได้มากขึ้น ในขณะเดียวกันก็อนุญาตให้เครื่องมือสแกนการโหลดล่วงหน้าค้นพบรูปภาพดังกล่าว

การแทรกทรัพยากรมากเกินไป

การแทรกในบรรทัดคือแนวทางปฏิบัติที่วางทรัพยากรภายใน HTML คุณสามารถใส่สไตล์ชีตในองค์ประกอบ <style>, สคริปต์ในองค์ประกอบ <script> และทรัพยากรอื่นๆ เกือบทั้งหมดโดยใช้การเข้ารหัส Base64

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

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

มาดูตัวอย่างจากหน้านี้ ในบางเงื่อนไข องค์ประกอบ LCP ที่เป็นไปได้คือรูปภาพที่อยู่ด้านบนของหน้า และ CSS อยู่ในไฟล์แยกต่างหากที่โหลดโดยองค์ประกอบ <link> หน้าเว็บนี้ยังใช้เว็บฟอนต์ 4 รายการที่ขอเป็นไฟล์แยกต่างหากจากทรัพยากร CSS ด้วย

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ของหน้าเว็บที่มีไฟล์ CSS ภายนอกซึ่งมีการอ้างอิงแบบอักษร 4 แบบ เครื่องมือสแกนการโหลดล่วงหน้าจะค้นพบรูปภาพ LCP ที่เป็นไปได้ในเวลาที่เหมาะสม
รูปที่ 12: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง LCP ที่เป็นไปได้ของหน้าคือรูปภาพที่โหลดจากองค์ประกอบ <img> แต่ได้รับการค้นพบโดยเครื่องมือสแกนการโหลดล่วงหน้าเนื่องจาก CSS และแบบอักษรที่จําเป็นสําหรับการโหลดหน้าเว็บอยู่ในทรัพยากรแยกต่างหาก ซึ่งไม่ทําให้เครื่องมือสแกนการโหลดล่วงหน้าทำงานล่าช้า

จะเกิดอะไรขึ้นหาก CSS และแบบอักษรทั้งหมดอยู่ในบรรทัดเดียวกันเป็นทรัพยากร Base64

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ของหน้าเว็บที่มีไฟล์ CSS ภายนอกซึ่งมีการอ้างอิงแบบอักษร 4 รายการ การสแกนเพื่อโหลดล่วงหน้าล่าช้าอย่างมากในการค้นพบรูปภาพ LCP
รูปที่ 13: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง LCP ที่เป็นไปได้ของหน้าเว็บคือรูปภาพที่โหลดจากองค์ประกอบ <img> แต่การแทรก CSS และทรัพยากรแบบอักษร 4 รายการใน " ทำให้เครื่องสแกนการโหลดล่วงหน้าตรวจไม่พบรูปภาพจนกว่าทรัพยากรเหล่านั้นจะดาวน์โหลดจนเสร็จสมบูรณ์

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

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

การโหลดล่วงหน้าช่วยแก้ปัญหานี้ได้ไหม เอาสิ คุณอาจโหลดรูปภาพ LCP ล่วงหน้าและลดเวลา LCP ได้ แต่การทำให้ HTML อาจมีขนาดใหญ่เกินกว่าที่จะแคชได้โดยใช้ทรัพยากรแบบแทรกในหน้าเว็บจะส่งผลเสียต่อประสิทธิภาพอื่นๆ First Contentful Paint (FCP) ก็ได้รับผลกระทบจากรูปแบบนี้ด้วย ในเวอร์ชันของหน้าเว็บที่ไม่มีบรรทัดแรก FCP อยู่ที่ประมาณ 2.7 วินาที ในเวอร์ชันที่ฝังทุกอย่างไว้ FCP อยู่ที่ประมาณ 5.8 วินาที

โปรดระมัดระวังอย่างยิ่งเมื่อแทรกข้อมูลลงใน HTML โดยเฉพาะแหล่งข้อมูลที่เข้ารหัส Base64 โดยทั่วไปเราไม่แนะนํา ยกเว้นในกรณีที่มีทรัพยากรขนาดเล็กมาก ใช้การฝังในบรรทัดน้อยที่สุดเท่าที่จะเป็นไปได้ เนื่องจากการใช้การฝังในบรรทัดมากเกินไปเป็นการกระทำที่เสี่ยง

การแสดงผลมาร์กอัปด้วย JavaScript ฝั่งไคลเอ็นต์

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

รูปแบบหนึ่งที่อาจหลบเลี่ยงการสแกนการโหลดล่วงหน้าได้คือการแสดงผลมาร์กอัปด้วย JavaScript ฝั่งไคลเอ็นต์ ดังนี้

Waterfall ของเครือข่าย WebPageTest ที่แสดงหน้าเว็บพื้นฐานที่มีรูปภาพและข้อความที่แสดงผลในไคลเอ็นต์ด้วย JavaScript อย่างสมบูรณ์ เนื่องจากมาร์กอัปอยู่ใน JavaScript เครื่องมือสแกนการโหลดล่วงหน้าจึงตรวจไม่พบทรัพยากรใดๆ ทรัพยากรทั้งหมดจะล่าช้าเพิ่มเติมเนื่องจากเครือข่ายและเวลาประมวลผลเพิ่มเติมที่เฟรมเวิร์ก JavaScript ต้องการ
รูปที่ 14: แผนภูมิ Waterfall ของเครือข่าย WebPageTest สำหรับหน้าเว็บที่แสดงผลโดยไคลเอ็นต์ที่ทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลอง เนื่องจากเนื้อหาอยู่ใน JavaScript และใช้เฟรมเวิร์กในการแสดงผล ทรัพยากรรูปภาพในมาร์กอัปที่แสดงผลโดยไคลเอ็นต์จึงซ่อนจากเครื่องมือสแกนการโหลดล่วงหน้า ประสบการณ์การใช้งานที่เทียบเท่าซึ่งแสดงผลจากเซิร์ฟเวอร์จะแสดงในรูปที่ 9

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

หัวข้อนี้ไม่ได้เกี่ยวข้องกับประเด็นหลักของบทความนี้มากนัก แต่ผลของการเรนเดอร์มาร์กอัปในไคลเอ็นต์นั้นส่งผลมากกว่าการเอาชนะเครื่องมือสแกนการโหลดล่วงหน้า ตัวอย่างเช่น การใช้ JavaScript เพื่อขับเคลื่อนประสบการณ์การใช้งานที่ไม่จําเป็นต้องใช้จะเพิ่มเวลาในการประมวลผลที่ไม่จําเป็น ซึ่งอาจส่งผลต่อ Interaction to Next Paint (INP) การแสดงผลมาร์กอัปจำนวนมากในไคลเอ็นต์มีแนวโน้มที่จะสร้างงานที่มีขนาดใหญ่มากกว่าเมื่อเทียบกับมาร์กอัปจำนวนเดียวกันที่เซิร์ฟเวอร์ส่ง สาเหตุที่ทำให้เกิดปัญหานี้ (นอกเหนือจากการประมวลผลเพิ่มเติมที่ JavaScript เกี่ยวข้อง) คือเบราว์เซอร์สตรีมมาร์กอัปจากเซิร์ฟเวอร์และแบ่งการแสดงผลออกเป็นส่วนๆ ในลักษณะที่มักจะจำกัดงานระยะยาว ในทางกลับกัน มาร์กอัปที่แสดงผลฝั่งไคลเอ็นต์จะได้รับการจัดการเป็นงานแบบโมโนลิธิคงานเดียว ซึ่งอาจส่งผลต่อ INP ของหน้า

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

หากหน้าเว็บต้องใช้ JavaScript เพื่อแนบฟังก์ชันการทำงานกับมาร์กอัปของหน้าเว็บบางส่วน คุณยังคงใช้ SSR ได้โดยใช้ JavaScript เวอร์ชันมาตรฐานหรือการไฮเดรตเพื่อใช้ทั้ง 2 รูปแบบร่วมกัน

ช่วยให้เครื่องมือสแกนแบบโหลดล่วงหน้าช่วยเหลือคุณได้

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

สรุปสิ่งที่คุณควรทราบจากโพสต์นี้

  • ตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์คือโปรแกรมแยกวิเคราะห์ HTML รองที่จะสแกนก่อนโปรแกรมแยกวิเคราะห์หลัก หากถูกบล็อกเพื่อค้นหาทรัพยากรที่ดึงข้อมูลได้เร็วขึ้น
  • เครื่องมือสแกนเพื่อโหลดล่วงหน้าจะตรวจไม่พบทรัพยากรที่ไม่ได้อยู่ในมาร์กอัปที่เซิร์ฟเวอร์ระบุในคำขอการนําทางครั้งแรก วิธีที่อาจหลบเลี่ยงการสแกนการโหลดล่วงหน้าได้ (แต่ไม่จํากัดเพียง) มีดังนี้
    • การแทรกทรัพยากรลงใน DOM ด้วย JavaScript ไม่ว่าจะเป็นสคริปต์ รูปภาพ สไตล์ชีต หรือสิ่งอื่นๆ ที่ควรอยู่ในเพย์โหลดมาร์กอัปเริ่มต้นจากเซิร์ฟเวอร์
    • การโหลดแบบ Lazy Loading สำหรับรูปภาพหรือ iframe ด้านบนส่วนแรกโดยใช้โซลูชัน JavaScript
    • การแสดงผลมาร์กอัปในไคลเอ็นต์ที่อาจมีการอ้างอิงถึงทรัพยากรย่อยของเอกสารโดยใช้ JavaScript
  • เครื่องมือสแกนการโหลดล่วงหน้าจะสแกนเฉพาะ HTML แต่จะไม่ได้ตรวจสอบเนื้อหาของทรัพยากรอื่นๆ โดยเฉพาะ CSS ที่อาจมีการอ้างอิงถึงชิ้นงานสำคัญ รวมถึง LCP ที่เป็นไปได้

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

แหล่งข้อมูล

รูปภาพหลักจาก Unsplash โดย Mohammad Rahmani