ในโมดูลก่อนหน้านี้ เราได้สำรวจทฤษฎีบางอย่างที่อยู่เบื้องหลังเส้นทางการแสดงผลวิกฤติ และดูว่าทรัพยากรที่บล็อกการแสดงผลและการบล็อกโปรแกรมแยกวิเคราะห์ทำให้การแสดงผลครั้งแรกของหน้าล่าช้าได้อย่างไร เมื่อคุณเข้าใจทฤษฎีเบื้องหลังสิ่งนี้แล้ว คุณก็พร้อมแล้วที่จะเรียนรู้เทคนิคบางอย่างในการเพิ่มประสิทธิภาพเส้นทางการแสดงผลวิกฤติ
ขณะที่หน้าเว็บโหลดขึ้น ระบบจะอ้างอิงทรัพยากรจำนวนมากภายใน HTML ของหน้าเว็บที่มีรูปลักษณ์และเลย์เอาต์ผ่าน CSS รวมถึงการโต้ตอบผ่าน JavaScript ในโมดูลนี้ แนวคิดสำคัญจำนวนหนึ่งที่เกี่ยวข้องกับทรัพยากรเหล่านี้และผลกระทบที่มีต่อเวลาในการโหลดหน้าเว็บครอบคลุม
แสดงผลการบล็อก
ตามที่ได้กล่าวไว้ในโมดูลก่อนหน้า CSS เป็นทรัพยากรการบล็อกการแสดงผล เนื่องจากบล็อกเบราว์เซอร์ไม่ให้แสดงผลเนื้อหาใดๆ จนกว่าจะมีการสร้างโมเดลออบเจ็กต์ CSS (CSSOM) เบราว์เซอร์จะบล็อกการแสดงผลเพื่อป้องกัน Flash ของเนื้อหาที่ไม่มีสไตล์ (FOUC) ซึ่งไม่พึงประสงค์ในแง่ของประสบการณ์ของผู้ใช้
ในวิดีโอก่อนหน้า มี FOUC สั้นๆ ที่คุณจะเห็นหน้าได้โดยไม่ต้องจัดรูปแบบ หลังจากนั้น จะมีการใช้สไตล์ทั้งหมดเมื่อ CSS ของหน้าเว็บโหลดจากเครือข่ายเสร็จสมบูรณ์ และเวอร์ชันที่ไม่มีสไตล์ของหน้านั้นถูกแทนที่ด้วยเวอร์ชันที่มีการจัดรูปแบบทันที
โดยทั่วไปแล้ว FOUC คือสิ่งที่ปกติแล้วคุณไม่เห็น แต่แนวคิด เป็นสิ่งสำคัญเพื่อจะได้รู้ว่าทำไมเบราว์เซอร์จึงบล็อกการแสดงผลหน้าเว็บจนกว่าจะมีการดาวน์โหลด CSS ไปใช้กับหน้าเว็บ การบล็อกการแสดงผลอาจไม่จำเป็นเสมอไป แต่คุณต้องการลดระยะเวลาโดยเพิ่มประสิทธิภาพ CSS อยู่เสมอ
การบล็อกโปรแกรมแยกวิเคราะห์
ทรัพยากรการบล็อกโปรแกรมแยกวิเคราะห์จะขัดจังหวะโปรแกรมแยกวิเคราะห์ HTML เช่น องค์ประกอบ <script>
ที่ไม่มีแอตทริบิวต์ async
หรือ defer
เมื่อโปรแกรมแยกวิเคราะห์พบองค์ประกอบ <script>
เบราว์เซอร์จะต้องประเมินและเรียกใช้สคริปต์ก่อนดำเนินการต่อด้วยการแยกวิเคราะห์ HTML ที่เหลือ เป็นเช่นนี้เพราะสคริปต์อาจแก้ไขหรือเข้าถึง DOM ในระหว่างการพัฒนา
<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>
เมื่อใช้ไฟล์ JavaScript ภายนอก (โดยไม่มี async
หรือ defer
) ระบบจะบล็อกโปรแกรมแยกวิเคราะห์เพื่อไม่ให้ตรวจพบไฟล์จนกว่าจะมีการดาวน์โหลด แยกวิเคราะห์ และดําเนินการ เมื่อใช้ JavaScript แบบอินไลน์ โปรแกรมแยกวิเคราะห์จะถูกบล็อกจนกว่าจะมีการแยกวิเคราะห์และเรียกใช้สคริปต์ในหน้า
ตัวสแกนการโหลดล่วงหน้า
เครื่องมือสแกนการโหลดล่วงหน้าคือการเพิ่มประสิทธิภาพเบราว์เซอร์ในรูปแบบของโปรแกรมแยกวิเคราะห์ HTML รอง ซึ่งจะสแกนการตอบสนอง HTML ดิบเพื่อค้นหาและดึงทรัพยากรก่อนที่โปรแกรมแยกวิเคราะห์ HTML หลักจะค้นพบทรัพยากรเหล่านั้น ตัวอย่างเช่น ตัวสแกนการโหลดล่วงหน้าจะอนุญาตให้เบราว์เซอร์เริ่มดาวน์โหลดทรัพยากรที่ระบุในองค์ประกอบ <img>
แม้ว่าโปรแกรมแยกวิเคราะห์ HTML จะถูกบล็อกขณะดึงข้อมูลและประมวลผลทรัพยากร เช่น CSS และ JavaScript ก็ตาม
หากต้องการใช้ประโยชน์จากเครื่องมือสแกนการโหลดล่วงหน้า คุณควรรวมทรัพยากรที่สำคัญไว้ในมาร์กอัป HTML ที่เซิร์ฟเวอร์ส่ง ตัวสแกนการโหลดล่วงหน้าไม่พบรูปแบบการโหลดทรัพยากรต่อไปนี้
- รูปภาพที่โหลดโดย CSS โดยใช้พร็อพเพอร์ตี้
background-image
การอ้างอิงรูปภาพเหล่านี้อยู่ใน CSS และตัวสแกนการโหลดล่วงหน้าจะไม่พบ - สคริปต์ที่โหลดแบบไดนามิกในรูปแบบมาร์กอัปองค์ประกอบ
<script>
ที่แทรกลงใน DOM โดยใช้ JavaScript หรือโมดูลที่โหลดโดยใช้import()
แบบไดนามิก - HTML ที่แสดงผลในไคลเอ็นต์โดยใช้ JavaScript มาร์กอัปดังกล่าวอยู่ภายในสตริงในทรัพยากร JavaScript และตัวสแกนการโหลดล่วงหน้าจะค้นพบไม่ได้
- การประกาศ
@import
ของ CSS
รูปแบบการโหลดทรัพยากรเหล่านี้เป็นทรัพยากรที่ค้นพบภายหลังทั้งหมด ดังนั้นจึงไม่ได้รับประโยชน์จากเครื่องสแกนการโหลดล่วงหน้า โปรดหลีกเลี่ยงทุกครั้งที่เป็นไปได้ อย่างไรก็ตาม หากหลีกเลี่ยงรูปแบบดังกล่าวไม่ได้ คุณอาจใช้คำแนะนำ preload
เพื่อหลีกเลี่ยงความล่าช้าในการค้นหาทรัพยากรได้
CSS
CSS จะกำหนดงานนำเสนอและเลย์เอาต์ของหน้าเว็บ ตามที่อธิบายไว้ก่อนหน้านี้ CSS เป็นทรัพยากรที่บล็อกการแสดงผล ดังนั้นการเพิ่มประสิทธิภาพ CSS จึงอาจมีผลกระทบอย่างมากต่อเวลาในการโหลดหน้าเว็บโดยรวม
การลดขนาด
การลดขนาดไฟล์ CSS จะช่วยลดขนาดไฟล์ของทรัพยากร CSS ทำให้ดาวน์โหลดได้เร็วขึ้น ซึ่งทำได้โดยการนำเนื้อหาออกจากไฟล์ CSS ต้นทาง เช่น การเว้นวรรคและอักขระอื่นๆ ที่มองไม่เห็น และส่งผลลัพธ์ไปยังไฟล์ที่เพิ่มประสิทธิภาพใหม่ ดังนี้
/* Unminified CSS: */
/* Heading 1 */
h1 {
font-size: 2em;
color: #000000;
}
/* Heading 2 */
h2 {
font-size: 1.5em;
color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}
รูปแบบพื้นฐานที่สุด การลดรูป CSS เป็นการเพิ่มประสิทธิภาพที่ได้ผลซึ่งอาจปรับปรุง FCP ของเว็บไซต์ได้ และบางทีอาจเป็น LCP ในบางกรณีด้วย เครื่องมือต่างๆ เช่น แพ็กเกจ จะเพิ่มประสิทธิภาพนี้ให้คุณโดยอัตโนมัติในเวอร์ชันที่ใช้งานจริง
นำ CSS ที่ไม่ได้ใช้ออก
ก่อนที่จะแสดงผลเนื้อหา เบราว์เซอร์จะต้องดาวน์โหลดและแยกวิเคราะห์สไตล์ชีตทั้งหมด เวลาที่ใช้ในการแยกวิเคราะห์ยังรวมถึงสไตล์ที่ไม่ได้ใช้ในหน้าปัจจุบันด้วย หากคุณใช้ Bundler ที่รวมทรัพยากร CSS ทั้งหมดเป็นไฟล์เดียว ผู้ใช้มีแนวโน้มที่จะดาวน์โหลด CSS มากกว่าจำนวนที่จำเป็นในการแสดงหน้าปัจจุบัน
หากต้องการค้นหา CSS ที่ไม่ได้ใช้สำหรับหน้าปัจจุบัน ให้ใช้เครื่องมือการครอบคลุมในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome
![ภาพหน้าจอของเครื่องมือการครอบคลุมในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ไฟล์ CSS ถูกเลือกไว้ที่บานหน้าต่างด้านล่าง ซึ่งแสดง CSS จำนวนมากที่การจัดวางหน้าเว็บปัจจุบันไม่ได้ใช้](https://web.dev/static/learn/performance/optimize-resource-loading/image/fig-1.png?authuser=6&hl=th)
การนำ CSS ที่ไม่ได้ใช้ออกมีผลกระทบ 2 ด้าน นอกเหนือจากการลดเวลาในการดาวน์โหลดแล้ว คุณยังเพิ่มประสิทธิภาพการสร้างโครงสร้างการแสดงผล เนื่องจากเบราว์เซอร์ต้องประมวลผลกฎ CSS น้อยลง
หลีกเลี่ยงการประกาศ @import
ของ CSS
แม้ว่าอาจจะดูสะดวก แต่ก็ควรหลีกเลี่ยงการประกาศ @import
ใน CSS ดังนี้
/* Don't do this: */
@import url('style.css');
การประกาศ @import
ใน CSS ช่วยให้คุณนำเข้าทรัพยากร CSS ภายนอกจากภายในสไตล์ชีตได้ เช่นเดียวกับวิธีการทำงานขององค์ประกอบ <link>
ใน HTML ความแตกต่างหลักระหว่าง 2 แนวทางนี้คือองค์ประกอบ HTML <link>
เป็นส่วนหนึ่งของการตอบสนอง HTML จึงค้นพบเร็วกว่าไฟล์ CSS ที่ดาวน์โหลดโดยการประกาศ @import
เนื่องจากเพื่อให้ระบบค้นพบการประกาศ @import
คุณจะต้องดาวน์โหลดไฟล์ CSS ที่มีไฟล์นี้ก่อน ซึ่งจะทำให้เกิดสิ่งที่เรียกว่าห่วงโซ่คำขอ ซึ่งในกรณีของ CSS จะทำให้หน้าเว็บใช้เวลาแสดงผลครั้งแรกล่าช้า ข้อเสียอีกประการหนึ่งคือสไตล์ชีตที่โหลดโดยใช้การประกาศ @import
จะค้นพบด้วยเครื่องสแกนการโหลดล่วงหน้าไม่ได้ จึงกลายเป็นทรัพยากรที่บล็อกการแสดงผลซึ่งค้นพบล่าช้า
<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">
ในกรณีส่วนใหญ่ คุณแทนที่ @import
ได้โดยใช้องค์ประกอบ <link rel="stylesheet">
องค์ประกอบ <link>
ช่วยให้ดาวน์โหลดสไตล์ชีตพร้อมกันและลดเวลาในการโหลดโดยรวมได้ ซึ่งต่างจากการประกาศ @import
ซึ่งจะดาวน์โหลดสไตล์ชีตติดต่อกัน
CSS สำคัญในบรรทัด
ระยะเวลาที่ใช้ในการดาวน์โหลดไฟล์ CSS จะเพิ่ม FCP ของหน้าเว็บได้ การกำหนดรูปแบบที่สำคัญในเอกสาร <head>
ทำให้ไม่มีคำขอเครือข่ายสำหรับทรัพยากร CSS และเมื่อดำเนินการอย่างถูกต้องจะช่วยปรับปรุงเวลาในการโหลดเริ่มต้นเมื่อแคชของเบราว์เซอร์ของผู้ใช้ไม่ได้เตรียมไว้ คุณโหลด CSS ที่เหลือแบบไม่พร้อมกันหรือต่อท้ายในตอนท้ายขององค์ประกอบ <body>
ได้
<head>
<title>Page Title</title>
<!-- ... -->
<style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
<!-- Other page markup... -->
<link rel="stylesheet" href="non-critical.css">
</body>
ข้อเสียเปรียบ การใส่ CSS จำนวนมากจะทำให้การตอบกลับ HTML เริ่มต้นมีไบต์มากขึ้น เนื่องจากทรัพยากร HTML มักไม่มีการแคชเป็นเวลานานมากหรือเลยไม่ได้ ระบบจึงไม่มีการแคช CSS แบบอินไลน์สำหรับหน้าถัดไปที่อาจใช้ CSS เดียวกันในสไตล์ชีตภายนอก ทดสอบและวัดประสิทธิภาพหน้าเว็บเพื่อให้แน่ใจว่าได้ผลตอบแทนที่คุ้มค่า
การสาธิต CSS
JavaScript
JavaScript กระตุ้นให้เกิดการโต้ตอบส่วนใหญ่บนเว็บ แต่ก็ต้องเสียค่าใช้จ่าย การจัดส่ง JavaScript มากเกินไปอาจทำให้หน้าเว็บตอบสนองช้าระหว่างการโหลดหน้าเว็บ และอาจก่อให้เกิดปัญหาการตอบสนองที่ทำให้การโต้ตอบช้าลง ซึ่งทั้งคู่อาจทำให้ผู้ใช้รู้สึกหงุดหงิด
JavaScript ที่บล็อกการแสดงผล
เมื่อโหลดองค์ประกอบ <script>
โดยไม่มีแอตทริบิวต์ defer
หรือ async
เบราว์เซอร์จะบล็อกการแยกวิเคราะห์และการแสดงผลจนกว่าจะมีการดาวน์โหลด แยกวิเคราะห์ และดําเนินการสคริปต์ ในทำนองเดียวกัน สคริปต์ในหน้าจะบล็อกโปรแกรมแยกวิเคราะห์จนกว่าสคริปต์จะได้รับการแยกวิเคราะห์และเรียกใช้
async
เจอกับ defer
async
และ defer
อนุญาตให้สคริปต์ภายนอกโหลดโดยไม่บล็อกโปรแกรมแยกวิเคราะห์ HTML ขณะที่สคริปต์ (รวมถึงสคริปต์ในหน้า) ที่มี type="module"
จะเลื่อนโดยอัตโนมัติ อย่างไรก็ตาม async
และ defer
มีความแตกต่างบางอย่างที่ควรทำความเข้าใจ
สคริปต์ที่โหลดด้วย async
จะได้รับการแยกวิเคราะห์และเรียกใช้ทันทีที่ดาวน์โหลด ส่วนสคริปต์ที่โหลดด้วย defer
จะทำงานเมื่อการแยกวิเคราะห์เอกสาร HTML เสร็จสิ้น ซึ่งจะเกิดขึ้นพร้อมกับเหตุการณ์ DOMContentLoaded
ของเบราว์เซอร์
นอกจากนี้ สคริปต์ async
อาจทํางานไม่เรียงตามลำดับ ส่วนสคริปต์ defer
จะทำงานตามลำดับที่ปรากฏในมาร์กอัป
การแสดงผลฝั่งไคลเอ็นต์
โดยทั่วไปคุณควรหลีกเลี่ยงการใช้ JavaScript ในการแสดงผลเนื้อหาที่สำคัญหรือองค์ประกอบ LCP ของหน้าเว็บ วิธีนี้เรียกว่าการแสดงผลฝั่งไคลเอ็นต์และเป็นเทคนิคที่ใช้อย่างแพร่หลายในแอปพลิเคชันหน้าเว็บเดียว (SPA)
มาร์กอัปที่แสดงผลโดย JavaScript จะเลื่อนตัวสแกนการโหลดล่วงหน้า เนื่องจากทรัพยากรที่อยู่ในมาร์กอัปที่แสดงผลโดยไคลเอ็นต์ไม่พบทรัพยากรดังกล่าว จึงอาจทำให้การดาวน์โหลดทรัพยากรที่สำคัญ เช่น รูปภาพ LCP ล่าช้า เบราว์เซอร์จะเริ่มดาวน์โหลดรูปภาพ LCP หลังจากเรียกใช้สคริปต์แล้ว และเพิ่มองค์ประกอบไปยัง DOM เท่านั้น ดังนั้น สคริปต์จะทำงานได้ก็ต่อเมื่อมีการค้นพบ ดาวน์โหลด และแยกวิเคราะห์สคริปต์แล้วเท่านั้น วิธีนี้เรียกว่าเชนคำขอที่สำคัญและควรหลีกเลี่ยง
นอกจากนี้ การแสดงผลมาร์กอัปโดยใช้ JavaScript มีแนวโน้มที่จะสร้างงานที่ใช้เวลานานมากกว่ามาร์กอัปที่ดาวน์โหลดจากเซิร์ฟเวอร์เพื่อตอบสนองต่อคำขอการนำทาง การใช้การแสดงผล HTML ฝั่งไคลเอ็นต์จำนวนมากอาจส่งผลเสียต่อเวลาในการตอบสนองของการโต้ตอบ โดยเฉพาะอย่างยิ่งในกรณีที่ DOM ของหน้าเว็บมีขนาดใหญ่มาก ซึ่งทริกเกอร์การแสดงผลที่สำคัญเมื่อ JavaScript แก้ไข DOM
การลดขนาด
เช่นเดียวกับ CSS การลดขนาด JavaScript จะลดขนาดไฟล์ของทรัพยากรสคริปต์ ซึ่งอาจทำให้ดาวน์โหลดได้เร็วขึ้นและทำให้เบราว์เซอร์เข้าสู่กระบวนการแยกวิเคราะห์และคอมไพล์ JavaScript ได้เร็วขึ้น
นอกจากนี้ การลดขนาด JavaScript ยังล้ำหน้าไปมากกว่าการลดขนาดเนื้อหาอื่นๆ เช่น CSS เมื่อมีการลดขนาด JavaScript จะไม่ได้เป็นเพียงการตัดข้อความ เช่น การเว้นวรรค แท็บ และความคิดเห็นเท่านั้น แต่สัญลักษณ์ใน JavaScript ต้นฉบับจะถูกตัดให้สั้นลง บางครั้งกระบวนการนี้เรียกว่าการขยายข้อมูล หากต้องการดูความแตกต่าง ให้ใช้ซอร์สโค้ด JavaScript ต่อไปนี้
// Unuglified JavaScript source code:
export function injectScript () {
const scriptElement = document.createElement('script');
scriptElement.src = '/js/scripts.js';
scriptElement.type = 'module';
document.body.appendChild(scriptElement);
}
เมื่อมีการขยายซอร์สโค้ด JavaScript ก่อนหน้า ผลลัพธ์อาจมีลักษณะคล้ายกับข้อมูลโค้ดต่อไปนี้
// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}
ในข้อมูลโค้ดก่อนหน้านี้ คุณจะเห็นว่าตัวแปร scriptElement
ที่มนุษย์อ่านได้ในแหล่งที่มานั้นถูกย่อลงเป็น t
เมื่อนำไปใช้กับคอลเล็กชันขนาดใหญ่ของสคริปต์ จะช่วยประหยัดค่าใช้จ่ายได้ค่อนข้างมาก โดยไม่ส่งผลต่อฟีเจอร์ที่ JavaScript เวอร์ชันที่ใช้งานจริงของเว็บไซต์มีให้
หากคุณใช้ Bundler ในการประมวลผลซอร์สโค้ดของเว็บไซต์ การขยายมักจะทำโดยอัตโนมัติสำหรับบิลด์ที่ใช้งานจริง ตัวระบุ เช่น Terser เป็นโปรแกรมที่กำหนดค่าได้อย่างยืดหยุ่นเช่นกัน ซึ่งช่วยให้คุณปรับระดับความเข้มงวดของอัลกอริทึมการขยายเพื่อประหยัดสูงสุดได้ อย่างไรก็ตาม ค่าเริ่มต้นสำหรับเครื่องมือการขยายใดๆ ก็มักจะเพียงพอแล้วสำหรับการรักษาความสมดุลระหว่างขนาดเอาต์พุตกับการคงความสามารถไว้
การสาธิต JavaScript
ทดสอบความรู้ของคุณ
ข้อใดคือวิธีที่ดีที่สุดในการโหลดไฟล์ CSS หลายไฟล์ในเบราว์เซอร์
@import
ของ CSS<link>
หลายรายการตัวสแกนการโหลดล่วงหน้าของเบราว์เซอร์ทำหน้าที่อะไร
<link rel="preload">
ในทรัพยากร HTML
เหตุใดเบราว์เซอร์จึงบล็อกการแยกวิเคราะห์ HTML ชั่วคราวโดยค่าเริ่มต้นเมื่อดาวน์โหลดทรัพยากร JavaScript
ถัดไป: ช่วยเหลือเบราว์เซอร์ด้วยคำแนะนำด้านแหล่งข้อมูล
ตอนนี้คุณเข้าใจแล้วว่าทรัพยากรที่โหลดในองค์ประกอบ <head>
ส่งผลต่อการโหลดหน้าเว็บเริ่มต้นและเมตริกต่างๆ อย่างไร ก็ได้เวลาไปต่อ ในโมดูลถัดไป เราจะสำรวจคำแนะนำเกี่ยวกับทรัพยากรและวิธีที่คำแนะนำจะช่วยให้คำแนะนำดีๆ แก่เบราว์เซอร์เพื่อเริ่มโหลดทรัพยากรและเปิดการเชื่อมต่อกับเซิร์ฟเวอร์แบบข้ามต้นทางเร็วกว่าที่เบราว์เซอร์จะไม่ใช้