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

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

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

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

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

เบราว์เซอร์ทุกตัวมีโปรแกรมแยกวิเคราะห์ 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 ที่ส่วนท้ายของเอกสารเพื่อให้ผลของการแยกวิเคราะห์และการเรนเดอร์ที่ถูกบล็อกมีน้อยที่สุด

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

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

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

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

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

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

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

ดังที่คุณเห็นในการแสดงภาพ 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>

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

การแสดงวิดีโอตามลำดับขั้นของเครือข่าย 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 ที่เป็นไปได้ของหน้าเว็บคือองค์ประกอบที่มีพร็อพเพอร์ตี้ background-image ของ CSS สิ่งที่จะเกิดขึ้นเมื่อโหลดทรัพยากรมีดังนี้

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงหน้าเว็บที่มีตัวเลือก LCP ซึ่งโหลดจาก CSS โดยใช้พร็อพเพอร์ตี้ภาพพื้นหลัง เนื่องจากรูปภาพ 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 ไม่ว่าจะเป็นสคริปต์ รูปภาพ สไตล์ชีต หรืออะไรก็ตามที่ควรปรับปรุงในเพย์โหลดมาร์กอัปเริ่มต้นจากเซิร์ฟเวอร์
    • การโหลดรูปภาพครึ่งหน้าบนหรือ iframe แบบ Lazy Loading โดยใช้โซลูชัน JavaScript
    • การแสดงผลมาร์กอัปในไคลเอ็นต์ที่อาจมีการอ้างอิงถึงทรัพยากรย่อยของเอกสารโดยใช้ JavaScript
  • เครื่องมือสแกนการโหลดล่วงหน้าจะสแกนเฉพาะ HTML เท่านั้น แต่จะไม่ตรวจสอบเนื้อหาของทรัพยากรอื่นๆ โดยเฉพาะ CSS ที่อาจมีการอ้างอิงถึงเนื้อหาที่สำคัญ รวมถึงตัวเลือก LCP

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

แหล่งข้อมูล

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