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

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

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- เป็นรูปแบบที่พบได้ทั่วไปในเครื่องมือโหลดแบบเลื่อนเวลาโหลดซึ่งทำงานด้วย JavaScript เมื่อเลื่อนรูปภาพไปยังวิวพอร์ต ตัวโหลดแบบเลื่อนช้าจะตัดคำนำหน้า data- ออก ซึ่งหมายความว่าในตัวอย่างก่อนหน้านี้ data-src จะกลายเป็น src การอัปเดตนี้จะแจ้งให้เบราว์เซอร์ดึงข้อมูลทรัพยากร

รูปแบบนี้จะไม่เป็นปัญหาจนกว่าจะนำไปใช้กับรูปภาพที่อยู่ในวิวพอร์ตในระหว่างการเริ่มต้นใช้งาน เนื่องจากตัวสแกนการโหลดล่วงหน้าไม่อ่านแอตทริบิวต์ data-src ในลักษณะเดียวกับแอตทริบิวต์ src (หรือ srcset) ระบบจึงไม่พบการอ้างอิงรูปภาพก่อนหน้านี้ ที่แย่ไปกว่านั้น รูปภาพยังโหลดล่าช้ากว่าปกติจนถึงหลังจากที่โปรแกรมโหลด JavaScript โหลด คอมไพล์ และดำเนินการแบบ Lazy Loading แล้ว

แผนภูมิ Waterfall ของเครือข่าย WebPageTest ที่แสดงการหน่วงเวลาของรูปภาพที่โหลดแบบเลื่อนเวลาอยู่ในวิวพอร์ตระหว่างการเริ่มต้น เนื่องจากเครื่องมือสแกนการโหลดล่วงหน้าของเบราว์เซอร์ไม่พบทรัพยากรรูปภาพ และโหลดเฉพาะเมื่อโหลด JavaScript ที่จําเป็นสําหรับการโหลดแบบเลื่อนเวลา รูปภาพถูกค้นพบช้ากว่าที่ควรจะเป็น
รูปที่ 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 ซึ่งหมายความว่าภาพไม่ขึ้นอยู่กับสคริปต์ในการโหลด ซึ่งหมายความว่าเครื่องมือสแกนการโหลดล่วงหน้าจะค้นพบภาพได้เร็วขึ้น
รูปที่ 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 โดยใช้พร็อพเพอร์ตี้ background-image เนื่องจากรูปภาพ 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 เพื่อขับเคลื่อนประสบการณ์การใช้งานที่ไม่จําเป็นต้องใช้จะเพิ่มเวลาในการประมวลผลที่ไม่จําเป็น ซึ่งอาจส่งผลต่อ Interaction to 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