ดูว่าตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์คืออะไร ช่วยเพิ่มประสิทธิภาพได้อย่างไร และคุณจะหลีกเลี่ยงปัญหานี้ได้อย่างไร
แง่มุมหนึ่งที่ถูกมองข้ามในการเพิ่มความเร็วหน้าเว็บคือการทำความเข้าใจบางอย่างเกี่ยวกับภายในเบราว์เซอร์ เบราว์เซอร์ทำการเพิ่มประสิทธิภาพบางอย่างเพื่อปรับปรุงประสิทธิภาพในแบบที่เราที่นักพัฒนาซอฟต์แวร์ทำไม่ได้ แต่ตราบใดที่การเพิ่มประสิทธิภาพเหล่านั้นไม่ขัดขวางการเพิ่มประสิทธิภาพนั้นโดยไม่ได้ตั้งใจ
การเพิ่มประสิทธิภาพเบราว์เซอร์ภายในเครื่องหนึ่งที่ต้องทำความเข้าใจก็คือตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ โพสต์นี้จะอธิบายวิธีการทำงานของเครื่องสแกนการโหลดล่วงหน้า และที่สำคัญกว่านั้นคือวิธีที่คุณสามารถหลีกเลี่ยงที่จะทำงานผิดพลาดได้
เครื่องสแกนการโหลดล่วงหน้าคืออะไร
ทุกเบราว์เซอร์มีโปรแกรมแยกวิเคราะห์ HTML หลักที่แปลงข้อมูลมาร์กอัปดิบและประมวลผลให้เป็นโมเดลออบเจ็กต์ ปัญหาทั้งหมดนี้จะเกิดขึ้นต่อไปจนกว่าโปรแกรมแยกวิเคราะห์จะหยุดชั่วคราวเมื่อพบทรัพยากรที่บล็อก เช่น สไตล์ช��ตที่โหลดโดยมีองค์ประกอบ <link>
หรือสคริปต์ที่โหลดด้วยเอลิเมนต์ <script>
โดยไม่มีแอตทริบิวต์ async
หรือ defer
<link>
สำหรับไฟล์ CSS ภายนอก ซึ่งจะบล็อกเบราว์เซอร์ไม่ให้แยกวิเคราะห์ส่วนที่เหลือของเอกสาร หรือแม้กระทั่งแสดงผลเอกสารใดๆ จนกว่าจะมีการดาวน์โหลดและแยกวิเคราะห์ CSS
ในกรณีของไฟล์ CSS ทั้งการแยกวิเคราะห์และการแสดงผลจะถูกบล็อกเพื่อป้องกันไม่ให้เนื้อหาที่ไม่มีการจัดรูปแบบ (FOUC) สว่างวาบขึ้นมา ซึ่งก็คือการดูหน้าเว็บเวอร์ชันที่ไม่มีการจัดรูปแบบได้เป็นเวลาสั้นๆ ก่อนที่รูปแบบจะถูกนำมาใช้
![หน้าแรกของ web.dev อยู่ในสถานะที่ไม่มีรูปแบบ (ซ้าย) และอยู่ในรูปแบบที่จัดรูปแบบแล้ว (ขวา)](https://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/static/articles/preload-scanner/image/a-webpagetest-network-wat-ebe04c09d25a6.png?hl=th)
<img>
แต่ตัวสแกนการโหลดล่วงหน้าค้นพบเนื่องจาก CSS และแบบอักษรที่จำเป็นสำหรับการโหลดหน้าเว็บในทรัพยากรแยกต่างหาก ซึ่งไม่ทำให้ตัวสแกนการโหลดล่วงหน้าทำงานไม่ได้
ตอนนี้จะเกิดอะไรขึ้นหาก CSS และแบบอักษรทั้งหมดแทรกในบรรทัดเป็นทรัพยากร base64
![แผนภูมิ Waterfall ของเครือข่าย WebPageTest ของหน้าเว็บที่มีไฟล์ CSS ภายนอกและอ้างอิงถึงแบบอักษร 4 แบบ เครื่องสแกนการโหลดล่วงหน้าจะล่าช้าอย่างมากจากการค้นหาอิมเมจ LCP](https://cdn.statically.io/img/web.developers.google.cn/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://cdn.statically.io/img/web.developers.google.cn/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