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

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

Jeremy Wagner
Jeremy Wagner

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

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

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

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

วันที่ WebPageTest Waterfall ที่แสดงวิธีใช้คำแนะนำทรัพยากร rel=preload เพื่อโปรโมตการค้นพบสคริปต์ที่แทรกแบบไม่พร้อมกัน แม้ว่าจะเป็นในลักษณะที่อาจทำให้เกิดผลข้างเคียงที่ไม่คาดคิดก็ตาม
รูปที่ 7: แผนภูมิ Waterfall เครือข่าย WebPageTest ของหน้าเว็บทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลองขึ้น หน้าเว็บมีสไตล์ชีตเดียวและสคริปต์ 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 เท่านั้น รูปภาพถูกค้นพบช้ากว่าที่ควรจะเป็น
รูปที่ 8: แผนภูมิ Waterfall เครือข่าย WebPageTest ของหน้าเว็บทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลองขึ้น ทรัพยากรรูปภาพจะโหลดแบบ Lazy Loading โดยไม่จำเป็น แม้ว่าจะมองเห็นได้ในวิวพอร์ตในระหว่างการเริ่มต้นใช้งาน วิธีนี้ช่วยแก้ปัญหาเครื่องสแกนการโหลดล่วงหน้าและทำให้เกิดการหน่วงเวลาโดยไม่จำเป็น

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

วิธีแก้ไขคือเปลี่ยนมาร์กอัปรูปภาพ

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

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

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

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

ภาพพื้นหลัง CSS

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

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

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

วันที่ แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงหน้าเว็บที่มีตัวเลือก LCP ซึ่งโหลดจาก CSS โดยใช้พร็อพเพอร์ตี้ภาพพื้นหลัง เนื่องจากอิมเมจของตัวเลือก LCP อยู่ในประเภททรัพยากรที่ตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ตรวจสอบไม่ได้ ทรัพยากรจึงล่าช้าจากการโหลดจนกว่าจะมีการดาวน์โหลดและประมวลผล CSS ซึ่งเป็นการหน่วงเวลาใน��ารแสดงผลของตัวเลือก LCP
รูปที่ 10: แผนภูมิ Waterfall เครือข่าย WebPageTest ของหน้าเว็บทำงานใน Chrome บนอุปกรณ์เคลื่อนที่ผ่านการเชื่อมต่อ 3G ที่จำลองขึ้น ตัวเลือก LCP ของหน้าเว็บเป็นองค์ประกอบที่มีพร็อพเพอร์ตี้ CSS 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 มิลลิวินาที
รูปที่ 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 โดยเฉพาะทรัพยากรที่เข้ารหัสฐาน 64 เราไม่แนะนำให้ทำเช่นนี้ ยกเว้นสำหรับทรัพยากรที่มีขนาดเล็กมาก แทรกในบรรทัดให้น้อยที่สุดเท่าที่จะเป็นไปได้ เนื่องจากอินไลน์มากเกินไปก็เล่นกับไฟ

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

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

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

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

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

แหล่งข้อมูล

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