ดูว่าตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์คืออะไร ช่วยเพิ่มประสิทธิภาพได้อย่างไร และคุณจะหลีกเลี่ยงปัญหานี้ได้อย่างไร
แง่มุมหนึ่งที่ถูกมองข้ามในการเพิ่มความเร็วหน้าเว็บคือการทำความเข้าใจองค์ประกอบภายในของเบราว์เซอร์ เบราว์เซอร์ทำการเพิ่มประสิทธิภาพบางอย่างเพื่อปรับปรุงประสิทธิภาพในแบบที่เราที่นักพัฒนาซอฟต์แวร์ทำไม่ได้ แต่ตราบใดที่การเพิ่มประสิทธิภาพเหล่านั้นไม่ขัดขวางการเพิ่มประสิทธิภาพนั้นโดยไม่ได้ตั้งใจ
การเพิ่มประสิทธิภาพเบราว์เซอร์ภายในที่ต้องทำความเข้าใจก็คือตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ โพสต์นี้จะอธิบายวิธีการทำงานของเครื่องสแกนการโหลดล่วงหน้า และที่สำคัญกว่านั้นคือวิธีที่คุณสามารถหลีกเลี่ยงที่จะทำงานผิดพลาดได้
เครื่องสแกนการโหลดล่วงหน้าคืออะไร
ทุกเบราว์เซอร์มีโปรแกรมแยกวิเคราะห์ HTML หลักที่แปลงข้อมูลมาร์กอัปดิบและประมวลผลให้เป็นโมเดลออบเจ็กต์ ปัญหาทั้งหมดนี้จะเกิดขึ้นต่อไปจนกว่าโปรแกรมแยกวิเคราะห์จะหยุดชั่วคราวเมื่อพบทรัพยากรที่บล็อก เช่น สไตล์ชีตที่โหลดโดยมีองค์ประกอบ <link>
หรือสคริปต์ที่โหลดด้วยเอลิเมนต์ <script>
โดยไม่มีแอตทริบิวต์ async
หรือ defer
<link>
สำหรับไฟล์ CSS ภายนอก ซึ่งจะบล็อกเบราว์เซอร์ไม่ให้แยกวิเคราะห์ส่วนที่เหลือของเอกสาร หรือแม้กระทั่งแสดงผลเอกสารใดๆ จนกว่าจะมีการดาวน์โหลดและแยกวิเคราะห์ CSS
ในกรณีของไฟล์ CSS ทั้งการแยกวิเคราะห์และการแสดงผลจะถูกบล็อกเพื่อป้องกันไม่ให้เนื้อหาที่ไม่มีการจัดรูปแบบ (FOUC) สว่างวาบขึ้นมา ซึ่งก็คือการดูหน้าเว็บเวอร์ชันที่ไม่มีการจัดรูปแบบได้เป็นเวลาสั้นๆ ก่อนที่รูปแบบจะถูกนำมาใช้
![หน้าแรกของ web.dev อยู่ในสถานะที่ไม่มีรูปแบบ (ซ้าย) และอยู่ในรูปแบบที่จัดรูปแบบแล้ว (ขวา)](https://web.dev/static/articles/preload-scanner/image/the-webdev-home-page-an-d03ddaf5d79f7.png?hl=th)
นอกจากนี้ เบราว์เซอร์ยังบล็อกการแยกวิเคราะห์และการแสดงผลของหน้าเมื่อพบองค์ประกอบ <script>
ที่ไม่มีแอตทริบิวต์ defer
หรือ async
กรณีนี้เกิดจากการที่เบราว์เซอร์ไม่ทราบอย่างแน่ชัดว่าสคริปต์ใดๆ จะแก้ไข DOM ขณะที่โปรแกรมแยกวิเคราะห์ HTML หลักยังคงทำงานอยู่หรือไม่ นี่คือเหตุผลทั่วไปในการโหลด JavaScript ที่ส่วนท้ายของเอกสารเพื่อให้ผลของการแยกวิเคราะห์และการแสดงผลที่ถูกบล็อกกลายเป็นส่วนเพิ่ม
นี่เป็นเหตุผลที่ดีว่าเหตุใดเบราว์เซอร์ควรบล็อกทั้งการแยกวิเคราะห์และการแสดงผล อย่างไรก็ตาม การดำเนินการในขั้นตอนสำคัญทั้ง 2 อย่างนี้ไม่เป็นที่ต้องการ เนื่องจากไม่อาจฉุดไม่อยู่ได้ เนื่องจากอาจทำให้ค้นพบแหล่งข้อมูลสำคัญอื่นๆ ล่าช้าออกไป โชคดีที่เบราว์เซอร์พยายามอย่างสุดความสามารถเพื่อลดปัญหาเหล่านี้ด้วยการใช้โปรแกรมแยกวิเคราะห์ HTML สำรองที่เรียกว่าเครื่องสแกนการโหลดล่วงหน้า
<body>
แต่ตัวสแกนการโหลดล่วงหน้าสามารถดูในมาร์กอัปข้อมูลดิบล่วงหน้า เพื่อค้นหาทรัพยากรรูปภาพดังกล่าวและเริ่มโหลดทรัพยากรดังกล่าวก่อนที่โปรแกรมแยกวิเคราะห์ HTML หลักจะถูกยกเลิกการบล็อก
บทบาทของเครื่องสแกนการโหลดล่วงหน้าเป็นแบบคาดเดา ซึ่งหมายความว่าโปรแกรมจะตรวจสอบมาร์กอัปดิบเพื่อค้นหาทรัพยากรสำหรับดึงข้อมูลตามโอกาสก่อนที่โปรแกรมแยกวิเคราะห์ HTML หลักจะพบ
วิธีดูว่าเครื่องสแกนการโหลดล่วงหน้าทำงานเมื่อใด
ตัวสแกนการโหลดล่วงหน้ามีอยู่เนื่องจากการแสดงผลและการแยกวิเคราะห์ถูกบล็อก หากไม่มีปัญหาด้านประสิทธิภาพทั้ง 2 อย่างนี้ ตัวสแกนการโหลดล่วงหน้าจะไม่มีประโยชน์มากนัก กุญแจสำคัญในการค้นหาว่าหน้าเว็บจะได้รับประโยชน์จากเครื่องสแกนการโหลดล่วงหน้าหรือไม่นั้นขึ้นอยู่กับปรากฏการณ์การบล็อกเหล่านี้ ในการดำเนินการดังกล่าว คุณสามารถกำหนดการหน่วงเวลาปลอมให้กับคำขอค้นหาว่าเครื่องสแกนการโหลดล่วงหน้าทำงานอยู่ที่ใด
ดูตัวอย่างจากหน้านี้ที่มีข้อความและรูปภาพพื้นฐาน เนื่องจากไฟล์ CSS บล็อกทั้งการแสดงผลและการแยกวิเคราะห์ คุณจึงมีการหน่วงเวลาปลอม 2 วินาทีสำหรับสไตล์ชีตผ่านบริการพร็อกซี การหน่วงเวลานี้ช่วยให้เห็นง่ายขึ้นใน Waterfall ของเครือข่ายซึ่งเครื่องสแกนการโหลดล่วงหน้าทำงานอยู่
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest แสดงการหน่วงเวลาปลอม 2 วินาทีที่กำหนดไว้ในสไตล์ชีต](https://web.dev/static/articles/preload-scanner/image/the-webpagetest-network-w-888b82cd76bf1.png?hl=th)
จากที่เห็นใน 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 นี้จะแสดงการสแกนการโหลดล่วงหน้าที่ดำเนินการเมื่อมีการแทรกสคริปต์](https://web.dev/static/articles/preload-scanner/image/this-webpagetest-chart-sh-d83c16fca193.png?hl=th)
async
ที่แทรกไว้ ตัวสแกนการโหลดล่วงหน้าไม่พบสคริปต์ในระยะบล็อกการแสดงผล เนื่องจากมีการแทรกสคริปต์ลงบนไคลเอ็นต์
เรามาดูรายละเอียดของสิ่งที่เกิดขึ้นที่นี่
- ใน 0 วินาที ระบบจะขอเอกสารหลัก
- เมื่อเวลา 1.4 วินาที ไบต์แรกของคำขอการนำทางจะมาถึง
- ที่เวลา 2.0 วินาที ระบบจะขอ CSS และรูปภาพ
- เนื่องจากโปรแกรมแยกวิเคราะห์ถูกบล็อกขณะโหลดสไตล์ชีต และ JavaScript ในหน้าที่แทรกสคริปต์
async
จะเข้ามาหลังจากสไตล์ชีตนั้นในวินาทีที่ 2.6 ฟังก์ชันที่สคริปต์มีให้จึงไม่พร้อมใช้งานโดยเร็วที่สุด
ซึ่งเป็นสิ่งที่ไม่ดี เพราะคำขอสำหรับสคริปต์จะเกิดขึ้นหลังจากที่ดาวน์โหลดสไตล์ชีตเสร็จแล้วเท่านั้น ซึ่งจะหน่วงเวลาสคริปต์ไม่ให้ทำงานโดยเร็วที่สุด ในทางตรงกันข้าม เนื่องจากเครื่องมือสแกนการโหลดล่วงหน้าค้นพบองค์ประกอบ <img>
ได้ในมาร์กอัปที่เซิร์ฟเวอร์ให้มา
ดังนั้นจะเกิดอะไรขึ้นหากคุณใช้แท็ก <script>
ปกติที่มีแอตทริบิวต์ async
แทนการแทรกสคริปต์ลงใน DOM
<script src="/yall.min.js" async></script>
นี่คือผลลัพธ์
![การแสดงวิดีโอตามลำดับขั้นของเครือข่าย WebPageTest ซึ่งแสดงวิธีการโหลดสคริปต์แบบไม่พร้อมกันโดยใช้องค์ประกอบสคริปต์ HTML ยังคงค้นพบได้โดยตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ แม้ว่าโปรแกรมแยกวิเคราะห์ HTML หลักของเบราว์เซอร์จะถูกบล็อกขณะดาวน์โหลดและประมวลผลสไตล์ชีต](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-02055245d5ef.png?hl=th)
async
<script>
รายการเดียว ตัวสแกนการโหลดล่วงหน้าจะค้นหาสคริปต์ในระหว่างขั้นตอนการบล็อกการแสดงผล และโหลดสคริปต์พร้อมกับ CSS
คุณอาจรู้สึกอยากแนะนำว่าปัญหาเหล่านี้สามารถแก้ไขได้โดยใช้ rel=preload
วิธีนี้ใช้ได้ผลอย่างแน่นอน แต่ก็อาจมีผลข้างเคียงบางอย่างเกิดขึ้น เพราะสุดท้ายแล้ว ทำไมถึงต้องใช้ rel=preload
เพื่อแก้ไขปัญหาที่สามารถหลีกเลี่ยงได้โดยไม่แทรกองค์ประกอบ <script>
ลงใน DOM
![WebPageTest Waterfall ที่แสดงวิธีใช้คำแนะนำทรัพยากร rel=preload เพื่อโปรโมตการค้นพบสคริปต์ที่แทรกแบบไม่พร้อมกัน แม้ว่าจะเป็นในลักษณะที่อาจทำให้เกิดผลข้างเคียงที่ไม่คาดคิดก็ตาม](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-waterfall-s-2f698a04955f.png?hl=th)
async
ที่แทรกเข้ามา แต่สคริปต์ async
จะโหลดไว้ล่วงหน้าเพื่อให้มั่นใจว่าสามารถค้นพบได้เร็วขึ้น
การโหลด "การแก้ไข" ล่วงหน้า ตรงนั้น แต่กลับทำให้เกิดปัญหาใหม่ คือสคริปต์ async
ในการสาธิต 2 รายการแรก แม้จะโหลดใน <head>
กลับโหลดที่ "ต่ำ" ลำดับความสำคัญ ในขณะที่สไตล์ชีตจะโหลดที่ "สูงสุด" ลำดับความสำคัญ ในการสาธิตครั้งล่าสุดที่มีการโหลดสคริปต์ async
ล่วงหน้า สไตล์ชีตจะยังคงโหลดที่ "สูงสุด" แต่ลำดับความสำคัญของสคริปต์เป็น "สูง"
เมื่อมีการเพิ่มลำดับความสำคัญของทรัพยากร เบราว์เซอร์จะจัดสรรแบนด์วิดท์ให้ทรัพยากรมากขึ้น ซึ่งหมายความว่าแม้ว่าสไตล์ชีตจะมีลำดับความสำคัญสูงสุด แต่ลำดับความสำคัญที่มากกว่าของสคริปต์อาจทำให้เกิดการช่วงชิงแบนด์วิดท์ได้ ซึ่งอาจเป็นปัจจัยหนึ่งที่ทำให้การเชื่อมต่อช้า หรือในกรณีที่ทรัพยากรมีปริมาณมาก
คำตอบในที่นี้นั้นตรงไปตรงมา: หากจำเป็นต้องใช้สคริปต์ในระหว่างการเริ่มต้น ก็อย่าทำลายเครื่องสแกนการโหลดล่วงหน้าด้วยการแทรกโค้ดลงใน DOM ทดสอบตำแหน่งองค์ประกอบ <script>
ตามความจำเป็นและกับแอตทริบิวต์ต่างๆ เช่น defer
และ async
การโหลดแบบ Lazy Loading ด้วย JavaScript
การโหลดแบบ Lazy Loading เป็นวิธีที่ดีในการอนุรักษ์ข้อมูล ซึ่งมักใช้กับรูปภาพ อย่างไรก็ตาม บางครั้งการโหลดแบบ Lazy Loading อาจมีผลกับรูปภาพที่ "ครึ่งหน้าบน" อย่างไม่ถูกต้อง
ซึ่งจะทำให้เกิดปัญหาที่อาจเกิดขึ้นกับการค้นพบทรัพยากรในกรณีที่เป็นกังวลเรื่องเครื่องสแกนการโหลดล่วงหน้า และอาจทำให้ต้องใช้เวลาโดยไม่จำเป็นในการค้นหาการอ้างอิงไปยังรูปภาพ ดาวน์โหลด ถอดรหัส และนำเสนอรูปภาพดังกล่าว ลองดูมาร์กอัปรูปภาพนี้เป็นตัวอย่าง
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
การใช้คำนำหน้า data-
เป็นรูปแบบที่พบได้ทั่วไปใน Lazy Loader ที่ทำงานด้วยระบบ JavaScript เมื่อเลื่อนรูปภาพลงในวิวพอร์ต ตัวโหลดแบบ Lazy Loading จะตัดคำนำหน้า data-
ซึ่งหมายความว่าในตัวอย่างก่อนหน้านี้ data-src
จะกลายเป็น src
การอัปเดตนี้จะแจ้งให้เบราว์เซอร์ดึงข้อมูลทรัพยากร
รูปแบบนี้จะไม่เป็นปัญหาจนกว่าจะนำไปใช้กับรูปภาพที่อยู่ในวิวพอร์ตในระหว่างการเริ่มต้นใช้งาน เนื่องจากเครื่องสแกนการโหลดล่วงหน้าไม่อ่านแอตทริบิวต์ data-src
ในลักษณะเดียวกับแอตทริบิวต์ src
(หรือ srcset
) ระบบจึงไม่พบการอ้างอิงรูปภาพก่อนหน้านี้ ที่แย่ไปกว่านั้น รูปภาพยังโหลดล่าช้าตั้งแต่หลังจากที่โปรแกรมโหลด JavaScript โหลด คอมไพล์ และเรียกใช้ด้วย
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงให้เห็นว่ารูปภาพที่โหลดแบบ Lazy Loading ซึ่งอยู่ในวิวพอร์ตในระหว่างการเริ่มต้นใช้งานนั้นอาจมีความล่าช้าหรือไม่ เนื่องจากตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ไม่พบทรัพยากรรูปภาพ และจะโหลดก็ต่อเมื่อ JavaScript ที่จำเป็นสำหรับการโหลดแบบ Lazy Loading เท่านั้น รูปภาพถูกค้นพบช้ากว่าที่ควรจะเป็น](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-6e823c2a1d7a6.png?hl=th)
ทั้งนี้ขึ้นอยู่กับขนาดของรูปภาพซึ่งอาจขึ้นอยู่กับขนาดของวิวพอร์ต และอาจเป็นองค์ประกอบที่ต้องการสำหรับ Largest Contentful Paint (LCP) เมื่อเครื่องสแกนการโหลดล่วงหน้าไม่สามารถดึงทรัพยากรรูปภาพล่วงหน้าแบบคาดเดาได้ ซึ่งอาจเป็นเพราะในระหว่างช่วงเวลาที่สไตล์ชีตบล็อกการแสดงผล LCP ได้รับผลกระทบ
วิธีแก้ไขคือเปลี่ยนมาร์กอัปรูปภาพ
<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
ซึ่งเป็นรูปแบบที่เหมาะสมที่สุดสำหรับรูปภาพที่อยู่ในวิวพอร์ตในระหว่างการเริ่มต้น เนื่องจากเครื่องสแกนการโหลดล่วงหน้าจะค้นหาและดึงทรัพยากรรูปภาพได้รวดเร็วยิ่งขึ้น
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงสถานการณ์การโหลดสำหรับอิมเมจในวิวพอร์ตในระหว่างการเริ่มต้นใช้งาน รูปภาพไม่ได้โหลดแบบ Lazy Loading ซึ่งหมายความว่ารูปภาพไม่ต้องพึ่งสคริปต์ในการโหลด ซึ่งหมายความว่าเครื่องสแกนการโหลดล่วงหน้าจะค้นหารูปภาพได้เร็วขึ้น](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-5e2602b834b47.png?hl=th)
ผลลัพธ์ที่ได้จากตัวอย่างง่ายๆ นี้คือการปรับปรุง LCP ทุกๆ 100 มิลลิวินาทีบนการเชื่อมต่อที่ช้า อาจดูเหมือนไม่ใช่การปรับปรุงครั้งใหญ่ แต่เมื่อคุณเห็นว่าโซลูชันนั้นเป็นการแก้ไขมาร์กอัปอย่างรวดเร็ว และหน้าเว็บส่วนใหญ่มีความซับซ้อนมากกว่าตัวอย่างชุดนี้ ซึ่งหมายความว่าผู้สมัคร LCP อาจต้องเผชิญกับแบนด์วิดท์กับทรัพยากรอื่นๆ จำนวนมาก ดังนั้นการเพิ่มประสิทธิภาพในลักษณะนี้จึงมีความสำคัญมากขึ้นเรื่อยๆ
ภาพพื้นหลัง CSS
โปรดทราบว่าตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์จะสแกนมาร์กอัป แต่จะไม่สแกนทรัพยากรประเภทอื่นๆ เช่น CSS ซึ่งอาจเกี่ยวข้องกับการดึงข้อมูลรูปภาพที่พร็อพเพอร์ตี้ background-image
อ้างอิง
เช่นเดียวกับ HTML เบราว์เซอร์จะประมวลผล CSS เป็นโมเดลออบเจ็กต์ของตัวเองหรือที่เรียกว่า CSSOM หากพบทรัพยากรภายนอกเมื่อมีการสร้าง CSSOM แล้ว จะมีการขอทรัพยากรเหล่านั้นทันทีที่ค้นพบ ไม่ใช่โดยตัวสแกนการโหลดล่วงหน้า
สมมติว่าตัวเลือก LCP ของหน้าเว็บเป็นองค์ประกอบที่มีพร็อพเพอร์ตี้ CSS background-image
ต่อไปนี้คือสิ่งที่จะเกิดขึ้นเมื่อทรัพยากรโหลดขึ้น
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงหน้าเว็บที่มีตัวเลือก LCP ซึ่งโหลดจาก CSS โดยใช้พร็อพเพอร์ตี้ภาพพื้นหลัง เนื่องจากอิมเมจของตัวเลือก LCP อยู่ในประเภททรัพยากรที่ตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ตรวจสอบไม่ได้ ทรัพยากรจึงล่าช้าจากการโหลดจนกว่าจะมีการดาวน์โหลดและประมวลผล CSS ซึ่งเป็นการหน่วงเวลาในการแสดงผลของตัวเลือก LCP](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-ca60b2c25fa52.png?hl=th)
background-image
(แถว 3) รูปภาพที่ส่งคำขอจะไม่เริ่มดึงข้อมูลจนกว่าโปรแกรมแยกวิเคราะห์ CSS จะพบ
ในกรณีนี้ เครื่องสแกนการโหลดล่วงหน้าไม่ได้ทำงานอย่างเต็มที่เนื่องจากไม่เกี่ยวข้อง อย่างไรก็ตาม หากตัวเลือก LCP ในหน้าเว็บมาจากพร็อพเพอร์ตี้ CSS background-image
คุณก็จะต้องโหลดรูปภาพดังกล่าวล่วงหน้าด้วยดังนี้
<!-- 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 มิลลิวินาที](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-8a47e283c7c66.png?hl=th)
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 ในเวลาที่กำหนด](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-ebe04c09d25a6.png?hl=th)
<img>
แต่ตัวสแกนการโหลดล่วงหน้าค้นพบเนื่องจาก CSS และแบบอักษรที่จำเป็นสำหรับการโหลดหน้าเว็บในทรัพยากรแยกต่างหาก ซึ่งไม่ทำให้ตัวสแกนการโหลดล่วงหน้าทำงานไม่ได้
ตอนนี้จะเกิดอะไรขึ้นหาก CSS และแบบอักษรทั้งหมดแทรกในบรรทัดเป็นทรัพยากร base64
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest ของหน้าเว็บที่มีไฟล์ CSS ภายนอกและอ้างอิงถึงแบบอักษร 4 แบบ เครื่องสแกนการโหลดล่วงหน้าจะล่าช้าอย่างมากจากการค้นหาอิมเมจ LCP](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-2cad0c33c7bdd.png?hl=th)
<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 โดยเฉพาะทรัพยากรที่เข้ารหัสฐาน 64 เราไม่แนะนำให้ทำเช่นนี้ ยกเว้นสำหรับทรัพยากรที่มีขนาดเล็กมาก แทรกในบรรทัดให้น้อยที่สุดเท่าที่จะเป็นไปได้ เนื่องจากอินไลน์มากเกินไปก็เล่นกับไฟ
การแสดงผลมาร์กอัปด้วย JavaScript ฝั่งไคลเอ็นต์
ดังนั้นจึงไม่ต้องสงสัยเลยว่า JavaScript ส่งผลต่อความเร็วหน้าเว็บอย่างแน่นอน นักพัฒนาแอปไม่เพียงแค่พึ่งพาเครื่องมือนี้ในการนำเสนอการโต้ตอบเท่านั้น แต่ยังมีแนวโน้มที่จะพึ่งพาเครื่องมือดังกล่าวเพื่อนำเสนอเนื้อหาด้วย ซึ่งจะช่วยให้นักพัฒนาแอปได้รับประสบการณ์การใช้งานที่ดีขึ้น แต่ประโยชน์สำหรับนักพัฒนาซอฟต์แวร์ไม่ได้ก่อให้เกิดประโยชน์สำหรับผู้ใช้เสมอไป
รูปแบบหนึ่งที่สามารถเอาชนะตัวสแกนการโหลดล่วงหน้าได้คือการแสดงผลมาร์กอัปด้วย JavaScript ฝั่งไคลเอ็นต์
![Waterfall เครือข่าย WebPageTest ที่แสดงหน้าเว็บพื้นฐานพร้อมด้วยรูปภาพและข้อความที่แสดงผลบนไคลเอ็นต์อย่างสมบูรณ์ใน JavaScript เนื่องจากมาร์กอัปอยู่ภายใน JavaScript ตัวสแกนการโหลดล่วงหน้าจึงไม่พบทรัพยากรใดๆ ทรัพยากรทั้งหมดล่าช้าเพิ่มเติมเนื่องจากเครือข่ายและเวลาในการประมวลผลที่เฟรมเวิร์ก JavaScript ต้องการเพิ่มเติม](https://web.dev/static/articles/preload-scanner/image/a-webpagetest-network-wat-9a4b1c22879f5.png?hl=th)
เมื่อเพย์โหลดมาร์กอัปอยู่ในและแสดงผลทั้งหมดโดย JavaScript ในเบราว์เซอร์ เครื่องสแกนการโหลดล่วงหน้าจะมองไม่เห็นทรัพยากรใดๆ ในมาร์กอัปนั้น วิธีนี้ทำให้การค้นหาทรัพยากรที่สำคัญล่าช้า ซึ่งจะส่งผลต่อ LCP อย่างแน่นอน ในกรณีของตัวอย่างเหล่านี้ คำขอรูปภาพ LCP มีความล่าช้าอย่างมาก เมื่อเทียบกับประสบการณ์การแสดงผลที่เทียบเท่าโดยเซิร์ฟเวอร์ซึ่งไม่ต้องใช้ JavaScript
บทความนี้อาจเปลี่ยนไปเล็กน้อย แต่ผลของการแสดงผลมาร์กอัปในไคลเอ็นต์นั้นมากกว่าที่เอาชนะตัวสแกนการโหลดล่วงหน้า ประการแรก การนำ JavaScript ไปใช้เพื่อขับเคลื่อนประสบการณ์ที่ไม่ต้องอาศัยเวลาประมวลผลที่ไม่จำเป็นซึ่งอาจส่งผลกระทบต่อการโต้ตอบกับ Next Paint (INP) การแสดงมาร์กอัปจํานวนมากในไคลเอ็นต์มีแนวโน้มที่จะสร้างงานที่ใช้เวลานาน เมื่อเทียบกับมาร์กอัปที่เซิร์ฟเวอร์ส่งในจำนวนที่เท่ากัน สาเหตุนอกเหนือจากการประมวลผลพิเศษที่ JavaScript ใช้แล้ว คือเบราว์เซอร์สตรีมมาร์กอัปจากเซิร์ฟเวอร์และแยกการแสดงผลในลักษณะที่มีแนวโน้มที่จะจำกัดงานที่ใช้เวลานาน ในทางกลับกัน มาร์กอัปที่แสดงผลโดยไคลเอ็นต์จะมีการจัดการเป็นงานเดี่ยวแบบโมโนลิธ ซึ่งอาจส่งผลต่อ INP ของหน้าเว็บ
การชดเชยในสถานการณ์นี้จะขึ้นอยู่กับคำตอบสำหรับคำถามนี้: มีสาเหตุใดหรือไม่ที่เซิร์ฟเวอร์ไม่สามารถให้มาร์กอัปของหน้าเว็บของคุณ แทนที่จะแสดงผลในไคลเอ็นต์ หากคำตอบคือ "ไม่" ควรพิจารณาการแสดงผลฝั่งเซิร์ฟเวอร์ (SSR) หรือมาร์กอัปที่สร้างขึ้นแบบคงที่หากทำได้ เนื่องจากจะช่วยให้เครื่องสแกนการโหลดล่วงหน้าค้นพบและดึงทรัพยากรที่สำคัญล่วงหน้าได้ตามความเหมาะสม
หากหน้าเว็บต้องการให้ JavaScript แนบฟังก์ชันการทำงานกับบางส่วนของมาร์กอัปหน้าเว็บ คุณก็ยังดำเนินการดังกล่าวได้โดยใช้ SSR ไม่ว่าจะด้วย vanilla JavaScript หรือ hydration เพื่อให้ได้ประโยชน์สูงสุดจากทั้ง 2 องค์ประกอบ
ช่วยให้เครื่องสแกนการโหลดล่วงหน้าช่วยคุณ
ตัวสแกนการโหลดล่วงหน้าเป็นการเพิ่มประสิทธิภาพเบราว์เซอร์ที่มีประสิทธิภาพสูง ซึ่งช่วยให้หน้าเว็บโหลดได้เร็วขึ้นในช่วงเริ่มต้น การหลีกเลี่ยงรูปแบบที่ทำลายความสามารถในการค้นพบทรัพยากรสำคัญล่วงหน้าไม่เพียงแค่ทำให้การพัฒนาง่ายขึ้นสำหรับคุณ แต่ยังเป็นการสร้างประสบการณ์ของผู้ใช้ที่ดียิ่งขึ้นซึ่งจะให้ผลลัพธ์ที่ดีกว่าในเมตริกจำนวนมาก ซึ่งรวมถึง Web Vitals บางอย่างด้วย
กล่าวโดยสรุปคือ คุณต้องนำสิ่งต่อไปนี้ออกจากโพสต์นี้
- ตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์เป็นโปรแกรมแยกวิเคราะห์ HTML รองที่สแกนก่อนโปรแกรมหลัก หากโปรแกรมถูกบล็อกไม่ให้ค้นพบทรัพยากรที่สามารถดึงข้อมูลได้เร็วกว่าตามโอกาส
- ตัวสแกนการโหลดล่วงหน้าจะไม่พบทรัพยากรที่ไม่ได้อยู่ในมาร์กอัปซึ่งเซิร์ฟเวอร์ในคำขอการนำทางเริ่มต้น วิธีที่เครื่องสแกนการโหลดล่วงหน้าอาจเอาชนะได้อาจรวมถึง (แต่ไม่จำกัดเพียง) สิ่งต่อไปนี้
- การแทรกทรัพยากรลงใน DOM ด้วย JavaScript ไม่ว่าจะเป็นสคริปต์ รูปภาพ สไตล์ชีต หรืออะไรก็ตามที่ควรปรับปรุงในเพย์โหลดมาร์กอัปเริ่มต้นจากเซิร์ฟเวอร์
- การโหลดรูปภาพครึ่งหน้าบนหรือ iframe แบบ Lazy Loading ด้วยโซลูชัน JavaScript
- แสดงผลมาร์กอัปบนไคลเอ็นต์ที่อาจมีการอ้างอิงทรัพยากรย่อยของเอกสารโดยใช้ JavaScript
- ตัวสแกนการโหลดล่วงหน้าจะสแกนเฉพาะ HTML เท่านั้น แต่จะไม่ตรวจสอบเนื้อหาของทรัพยากรอื่นๆ โดยเฉพาะ CSS ที่อาจมีการอ้างอิงถึงเนื้อหาที่สำคัญ รวมถึงตัวเลือก LCP
หากคุณไม่สามารถหลีกเลี่ยงรูปแบบที่ส่งผลเสียต่อความสามารถของเครื่องสแกนการโหลดล่วงหน้าเพื่อเร่งประสิทธิภาพการโหลดได้ ไม่ว่าจะด้วยเหตุผลใดก็ตาม โปรดพิจารณาคำแนะนำเกี่ยวกับแหล่งข้อมูล rel=preload
หากคุณใช้ rel=preload
ให้ทดสอบในเครื่องมือห้องทดลองเพื่อให้แน่ใจว่าเครื่องมือจะให้ผลตามที่คุณต้องการ สุดท้ายนี้ อย่าโหลดทรัพยากรล่วงหน้ามากเกินไป เพราะเมื่อคุณจัดลำดับความสำคัญทุกอย่างจะไม่มีอะไรเกิดขึ้น
แหล่งข้อมูล
- "สคริปต์อะซิงโครนัส" ที่มีการแทรกสคริปต์ ถือว่าเป็นอันตราย
- วิธีที่ตัวโหลดล่วงหน้าของเบราว์เซอร์ทำให้หน้าเว็บโหลดเร็วขึ้น
- โหลดเนื้อหาที่สำคัญล่วงหน้าเพื่อปรับปรุงความเร็วในการโหลด
- สร้างการเชื่อมต่อเครือข่ายตั้งแต่เนิ่นๆ เพื่อเพิ่มความเร็วหน้าเว็บที่รับรู้
- การเพิ่มประสิทธิภาพ Largest Contentful Paint
รูปภาพหลักจาก Unsplash โดย Mohammad Rahmani