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

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

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

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

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

เบราว์เซอร์ทุกตัวมีโปรแกรมแยกวิเคราะห์ 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