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

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

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: แผนภูมิน้ำตกเครือข่าย 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