การตัดสินใจหลักอย่างหนึ่งที่นักพัฒนาเว็บต้องทำคือบริเวณที่จะใช้ตรรกะและแสดงผลในแอปพลิเคชันของตน ซึ่งอาจทำได้ยากเนื่องจากมีวิธีมากมาย ในการสร้างเว็บไซต์
การทำความเข้าใจเกี่ยวกับประเด็นนี้เกิดขึ้นจากงานของ Chrome ซึ่งพูดคุยกับเว็บไซต์ขนาดใหญ่ในช่วง 2-3 ปีที่ผ่านมา หรือพูดกว้างๆ ก็คือเราแนะนำให้นักพัฒนาซอฟต์แวร์พิจารณาการแสดงผลฝั่งเซิร์ฟเวอร์หรือแบบภาพนิ่งมากกว่าวิธีการรีไฮไลท์เต็มรูปแบบ
เพื่อให้เข้าใจสถาปัตยกรรมที่เราเลือกได้ดีขึ้นเมื่อตัดสินใจในเรื่องนี้ เราต้องมีความเข้าใจที่ชัดเจนเกี่ยวกับแต่ละแนวทางและคำศัพท์ที่สอดคล้องกันที่จะใช้เมื่อกล่าวถึง ความแตกต่างระหว่างวิธีการแสดงผลช่วยให้เห็นข้อดีและข้อเสียของการแสดงผลในเว็บจากมุมมองเกี่ยวกับประสิทธิภาพของหน้าเว็บ
คำศัพท์
การแสดงผล
- การแสดงผลฝั่งเซิร์ฟเวอร์ (SSR)
- การแสดงผลฝั่งไคลเอ็นต์หรือ Universal App เป็น HTML บนเซิร์ฟเวอร์
- การแสดงผลฝั่งไคลเอ็นต์ (CSR)
- แสดงผลแอปในเบราว์เซอร์โดยใช้ JavaScript เพื่อแก้ไข DOM
- การเติมน้ำ
- มุมมอง JavaScript "กำลังบูต" ในไคลเอ็นต์เพื่อให้มีการใช้แผนผัง DOM และข้อมูล DOM ของ HTML ที่แสดงผลโดยเซิร์ฟเวอร์ซ้ำ
- การแสดงผลล่วงหน้า
- การเรียกใช้แอปพลิเคชันฝั่งไคลเอ็นต์ ณ เวลาบิลด์เพื่อบันทึกสถานะเริ่มต้นเป็น HTML แบบคงที่
การแสดง
- เวลาที่ได้รับข้อมูลไบต์แรก (TTFB)
- เวลาระหว่างการคลิกลิงก์และไบต์แรกของเนื้อหาที่โหลดในหน้าใหม่
- First Contentful Paint (FCP)
- เวลาที่เนื้อหาที่ขอ (เนื้อหาบทความ ฯลฯ) จะแสดงให้เห็น
- การโต้ตอบกับ Next Paint (INP)
- เมตริกตัวแทนที่ประเมินว่าหน้าเว็บตอบสนองต่อข้อมูลจากผู้ใช้อย่างรวดเร็วอย่างสม่ำเสมอหรือไม่
- เวลาทั้งหมดในการบล็อก (TBT)
- เมตริกพร็อกซีสำหรับ INP ที่คำนวณระยะเวลาที่เทรดหลักถูกบล็อกระหว่างการโหลดหน้าเว็บ
การแสดงผลฝั่งเซิร์ฟเวอร์
การแสดงผลฝั่งเซิร์ฟเวอร์จะสร้าง HTML แบบเต็มสำหรับหน้าบนเซิร์ฟเวอร์เพื่อตอบสนองต่อการนำทาง วิธีนี้จะช่วยไม่ให้มีการเดินทางไป-กลับเพิ่มเติมเพื่อดึงข้อมูลและสร้างเทมเพลตในไคลเอ็นต์ เนื่องจากตัวแสดงผลจะจัดการข้อมูลเหล่านี้ก่อนที่เบราว์เซอร์จะได้รับการตอบสนอง
โดยทั่วไปการแสดงผลฝั่งเซิร์ฟเวอร์จะให้ FCP ที่รวดเร็ว การเรียกใช้ตรรกะของหน้าเว็บและการแสดงผลบนเซิร์ฟเวอร์ช่วยให้คุณหลีกเลี่ยงการส่ง JavaScript จำนวนมากไปยังไคลเอ็นต์ได้ วิธีนี้ช่วยลด TBT ของหน้าเว็บซึ่งอาจทำให้ INP ลดลงด้วย เนื่องจากเทรดหลักไม่ได้ถูกบล็อกบ่อยนักในระหว่างการโหลดหน้าเว็บ เมื่อเทรดหลักถูกบล็อกไม่บ่อยนัก การโต้ตอบของผู้ใช้จะมีโอกาสเกิดขึ้นเร็วขึ้น ซึ่งก็สมเหตุสมผลดี เพราะการแสดงผลฝั่งเซิร์ฟเวอร์ทำได้แค่เพียงส่งข้อความและลิงก์ไปที่เบราว์เซอร์ของผู้ใช้ วิธีนี้ได้ผลดีกับหลากหลายอุปกรณ์และสภาวะของเครือข่าย และเป็นการเพิ่มประสิทธิภาพเบราว์เซอร์ที่น่าสนใจ เช่น การแยกวิเคราะห์เอกสารสตรีมมิง
![แผนภาพแสดงการแสดงผลฝั่งเซิร์ฟเวอร์และการดำเนินการ JS ที่ส่งผลต่อ FCP และ TTI](https://web.dev/static/articles/rendering-on-the-web/image/diagram-showing-server-si-4c081d80ab5fe.png?authuser=6&hl=th)
ด้วยการแสดงผลฝั่งเซิร์ฟเวอร์ ผู้ใช้มักจะไม่ต้องรอให้ JavaScript ที่ผูกกับ CPU ทำงานก่อนที่จะใช้เว็บไซต์ของคุณได้ แม้ว่าคุณจะไม่สามารถหลีกเลี่ยง JS ของบุคคลที่สามได้ แต่การใช้การแสดงผลฝั่งเซิร์ฟเวอร์เพื่อลดค่าใช้จ่าย JavaScript ของบุคคลที่หนึ่งเองจะช่วยให้คุณได้รับงบประมาณเพิ่มขึ้นสำหรับส่วนที่เหลือ อย่างไรก็ตาม อาจมีข้อเสียบางอย่างสำหรับวิธีนี้ คือการสร้างหน้าเว็บบนเซิร์ฟเวอร์ต้องใช้เวลา ซึ่งสามารถเพิ่ม TTFB ของหน้าเว็บของคุณได้
การแสดงผลฝั่งเซิร์ฟเวอร์จะเพียงพอสำหรับแอปพลิเคชันของคุณหรือไม่นั้น ส่วนใหญ่แล้วจะขึ้นอยู่กับประเภทของประสบการณ์ที่คุณกำลังสร้าง มีการถกเถียงกันมาอย่างยาวนานเกี่ยวกับแอปพลิเคชันที่ถูกต้องของการแสดงผลฝั่งเซิร์ฟเวอร์กับการแสดงผลฝั่งไคลเอ็นต์ แต่คุณเลือกใช้การแสดงผลฝั่งเซิร์ฟเวอร์กับบางหน้าเท่านั้นไม่ได้ เว็บไซต์บางแห่งได้นำเทคนิคการแสดงผลแบบไฮบริดที่ประสบความสำเร็จมาใช้ ตัวอย่างเช่น เซิร์ฟเวอร์ของ Netflix แสดงผลหน้า Landing Page ที่ค่อนข้างคงที่ ขณะที่ดึงข้อมูล JS ล่วงหน้าสำหรับหน้าเว็บที่มีการโต้ตอบสูง ทำให้หน้าที่แสดงผลโดยไคลเอ็นต์ที่หนักขึ้นเหล่านี้มีโอกาสสูงขึ้นที่จะโหลดได้เร็วขึ้น
เฟรมเวิร์ก ไลบรารี และสถาปัตยกรรมที่ทันสมัยจำนวนมากช่วยให้คุณแสดงผลแอปพลิเคชันเดียวกันทั้งบนไคลเอ็นต์และเซิร์ฟเวอร์ได้ คุณสามารถใช้เทคนิคเหล่านี้ สำหรับการแสดงผลฝั่งเซิร์ฟเวอร์ อย่างไรก็ตาม สถาปัตยกรรมที่มีการแสดงผลทั้งบนเซิร์ฟเวอร์และไคลเอ็นต์เป็นโซลูชันระดับตัวมันเองซึ่งมีคุณลักษณะด้านประสิทธิภาพและข้อดีข้อเสียต่างกันมาก ผู้ใช้ React สามารถใช้ Server DOM API หรือโซลูชันที่สร้างขึ้นจากผู้ใช้ เช่น Next.js สำหรับการแสดงผลฝั่งเซิร์ฟเวอร์ ผู้ใช้ Vue จะใช้คู่มือการแสดงผลฝั่งเซิร์ฟเวอร์หรือ Nuxt ของ Vue ได้ Angular มี Universal อย่างไรก็ตาม โซลูชันที่ได้รับความนิยมมากที่สุดจะใช้การเติมน้ำบางรูปแบบ ดังนั้นโปรดคำนึงถึงวิธีการที่เครื่องมือของคุณใช้
การแสดงผลแบบคงที่
การแสดงผลแบบคงที่เกิดขึ้นในเวลาบิลด์ แนวทางนี้ให้ FCP ที่เร็ว รวมถึง TBT และ INP ที่ต่ำกว่า ตราบใดที่คุณจำกัดจำนวน JS ฝั่งไคลเอ็นต์ในหน้าเว็บ และยังให้ผลลัพธ์ TTFB ที่รวดเร็วอย่างต่อเนื่อง ซึ่งต่างจากการแสดงผลฝั่งเซิร์ฟเวอร์ เนื่องจากไม่จำเป็นต้องสร้าง HTML แบบไดนามิกบนเซิร์ฟเวอร์ โดยทั่วไปแล้ว การแสดงผลแบบคงที่หมายถึงการสร้างไฟล์ HTML แยกกันสำหรับ URL แต่ละรายการล่วงหน้า ด้วยการตอบสนอง HTML ที่สร้างขึ้นล่วงหน้าทำให้คุณทำให้การแสดงผลแบบคงที่ใช้งานได้กับ CDN หลายๆ แห่งเพื่อใช้ประโยชน์จากการแคช Edge
![แผนภาพที่แสดงการแสดงผลแบบคงที่และการดำเนินการ JS ที่ไม่บังคับซึ่งส่งผลต่อ FCP และ TTI](https://web.dev/static/articles/rendering-on-the-web/image/diagram-showing-static-re-0659f8679c321.png?authuser=6&hl=th)
โซลูชันสำหรับการแสดงผลแบบคงที่มีหลายรูปแบบและหลายขนาด เครื่องมืออย่างเช่น Gatsby ออกแบบมาเพื่อทำให้นักพัฒนาซอฟต์แวร์รู้สึกว่าแอปพลิเคชันของตนแสดงผลแบบไดนามิก ไม่ได้สร้างเป็นขั้นตอนการสร้าง เครื่องมือสร้างเว็บไซต์แบบคงที่ เช่น 11ty, Jekyll และ Metalsmith โอบรับสิ่งที่อยู่นิ่งๆ โดยแนวทางที่อิงตามเทมเพลตที่มากขึ้น
ข้อเสียประการหนึ่งของการแสดงผลแบบคงที่คือ ต้องมีการสร้างไฟล์ HTML แต่ละไฟล์สำหรับ URL ที่เป็นไปได้ทั้งหมด ซึ่งอาจทำให้เกิดความท้าทายหรือเป็นสิ่งที่ทำไม่ได้เลยเมื่อคุณไม่สามารถคาดการณ์ล่วงหน้าว่า URL เหล่านั้นจะเป็น URL ใดได้ หรือสำหรับเว็บไซต์ที่มีหน้าที่ไม่ซ้ำจำนวนมาก
ผู้ใช้ React อาจคุ้นเคยกับ Gatsby, การส่งออกแบบคงที่ของ Next.js หรือ Navi ซึ่งทั้งหมดนี้ช่วยให้สร้างหน้าเว็บจากคอมโพเนนต์ได้อย่างสะดวก อย่างไรก็ตาม การแสดงผลแบบคงที่และการแสดงผลล่วงหน้าจะมีลักษณะต่างกันไป นั่นคือ หน้าเว็บที่แสดงผลแบบคงที่จะเป็นแบบอินเทอร์แอ็กทีฟโดยไม่ต้องเรียกใช้ JavaScript ฝั่งไคลเอ็นต์มากนัก ขณะที่การแสดงผลล่วงหน้าจะช่วยปรับปรุง FCP ของแอปพลิเคชันหน้าเว็บเดียวที่ต้องบูตบนไคลเอ็นต์เพื่อทำให้หน้าเว็บโต้ตอบได้อย่างแท้จริง
หากคุณไม่แน่ใจว่าโซลูชันที่ระบุเป็นการแสดงผลแบบคงที่หรือการแสดงผลล่วงหน้า ให้ลองปิดใช้งาน JavaScript และโหลดหน้าเว็บที่คุณต้องการทดสอบ สําหรับหน้าเว็บที่แสดงผลแบบคงที่ ฟีเจอร์แบบอินเทอร์แอกทีฟส่วนใหญ่จะยังคงอยู่โดยไม่มี JavaScript หน้าที่แสดงผลล่วงหน้าอาจยังคงมีฟีเจอร์พื้นฐานบางอย่าง เช่น ลิงก์ที่ปิดใช้ JavaScript แต่ส่วนใหญ่แล้วหน้าจะไม่มีการใช้งาน
การทดสอบที่มีประโยชน์อีกอย่างคือการใช้การควบคุมเครือข่ายในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome และดูจำนวนการดาวน์โหลด JavaScript ก่อนที่หน้าเว็บจะโต้ตอบได้ โดยทั่วไปการแสดงผลล่วงหน้าต้องใช้ JavaScript มากกว่าจึงจะโต้ตอบได้ และ JavaScript มักมีความซับซ้อนกว่าวิธีการเพิ่มประสิทธิภาพแบบก้าวหน้าที่ใช้ในการแสดงผลแบบคงที่
การแสดงผลฝั่งเซิร์ฟเวอร์เทียบกับการแสดงผลแบบคงที่
การแสดงผลฝั่งเซิร์ฟเวอร์ไม่ใช่โซลูชันที่ดีที่สุดสำหรับทุกสิ่ง เนื่องจากลักษณะแบบไดนามิกอาจมีต้นทุนในการดำเนินการประมวลสูง โซลูชันการแสดงผลฝั่งเซิร์ฟเวอร์จำนวนมากไม่ได้ล้างออกก่อนกำหนด ทำให้ TTFB ล่าช้า หรือเพิ่มการส่งข้อมูลเป็น 2 เท่า (เช่น สถานะในบรรทัดซึ่ง JavaScript ในไคลเอ็นต์ใช้) ใน React renderToString()
อาจทำงานช้าเนื่องจากเป็นการทำงานแบบซิงโครนัสและเทรดเดี่ยว
DOM API ของเซิร์ฟเวอร์ React รุ่นใหม่รองรับสตรีมมิง ซึ่งสามารถรับส่วนแรกของการตอบสนอง HTML ไปยังเบราว์เซอร์เร็วขึ้นขณะที่ส่วนที่เหลือของเซิร์ฟเวอร์ยังสร้างขึ้นบนเซิร์ฟเวอร์
การใช้การแสดงผลฝั่งเซิร์ฟเวอร์ "ถูกต้อง" อาจเกี่ยวข้องกับการค้นหาหรือสร้างโซลูชันสำหรับการแคชคอมโพเนนต์ การจัดการการใช้หน่วยความจำ การใช้เทคนิคการบันทึกความทรงจำ และข้อกังวลอื่นๆ คุณมักจะประมวลผลหรือสร้างแอปเดิมใหม่ 2 ครั้ง โดย 1 ครั้งในไคลเอ็นต์และ 1 ครั้งบนเซิร์ฟเวอร์ การแสดงผลฝั่งเซิร์ฟเวอร์ที่แสดงเนื้อหาเสร็จเร็วขึ้นไม่ได้ทำให้คุณต้องทำงานน้อยลงเสมอไป หากคุณมีงานจำนวนมากในไคลเอ็นต์หลังจากที่มีการตอบสนอง HTML ที่เซิร์ฟเวอร์สร้างขึ้นในไคลเอ็นต์ การทำเช่นนี้ยังอาจทำให้มี TBT และ INP ของเว็บไซต์สูงขึ้น
การแสดงผลฝั่งเซิร์ฟเวอร์จะสร้าง HTML ตามคำขอสำหรับ URL แต่ละรายการ แต่อาจช้ากว่าการแสดงเนื้อหาที่แสดงผลแบบคงที่เพียงอย่างเดียว หากคุณทุ่มเททำงานเพิ่มเติมได้ การแสดงผลฝั่งเซิร์ฟเวอร์และการแคช HTML จะลดเวลาในการแสดงผลของเซิร์ฟเวอร์ได้อย่างมาก ประโยชน์ที่จะได้รับจากการแสดงผลฝั่งเซิร์ฟเวอร์คือความสามารถในการดึงข้อมูล "สด" ได้มากกว่าและตอบสนองต่อชุดคำขอที่สมบูรณ์มากกว่าที่เป็นไปได้ด้วยการแสดงผลแบบคงที่ หน้าที่ต้องการการปรับเปลี่ยนในแบบของคุณคือตัวอย่างที่ชัดเจนของประเภทคำขอที่ทำงานได้ไม่ดีกับการแสดงผลแบบคงที่
การแสดงผลฝั่งเซิร์ฟเวอร์ยังนำเสนอการตัดสินใจที่น่าสนใจเมื่อสร้าง PWA อีกด้วย กล่าวคือ ควรใช้การแคชService Worker แบบเต็มหน้าหรือเฉพาะการแสดงผลเนื้อหาแต่ละส่วนโดยเซิร์ฟเวอร์
การแสดงผลฝั่งไคลเอ็นต์
การแสดงผลฝั่งไคลเอ็นต์หมายถึงการแสดงผลหน้าเว็บในเบราว์เซอร์โดยตรงด้วย JavaScript ระบบจะจัดการตรรกะ การดึงข้อมูล เทมเพลต และการกำหนดเส้นทางทั้งหมดในไคลเอ็นต์ ไม่ใช่บนเซิร์ฟเวอร์ ผลลัพธ์ที่มีประสิทธิภาพคือจะมีการส่งข้อมูลไปยังอุปกรณ์ของผู้ใช้จากเซิร์ฟเวอร์มากขึ้น และมาพร้อมกับชุดการแลกเปลี่ยนของตัวเอง
การแสดงผลฝั่งไคลเอ็นต์อาจสร้างได้ยากและคงความเร็วไว้สำหรับอุปกรณ์เคลื่อนที่
การลงแรงเล็กๆ น้อยๆ เพื่อรักษางบประมาณ JavaScript ให้คงที่และนำส่งมูลค่าในไปกลับน้อยที่สุดเท่าที่จะเป็นไปได้ คุณสามารถรับการแสดงผลฝั่งไคลเอ็นต์เพื่อจำลองประสิทธิภาพการแสดงผลฝั่งเซิร์ฟเวอร์ที่แท้จริง คุณสามารถทำให้โปรแกรมแยกวิเคราะห์ทำงานให้คุณได้เร็วขึ้นด้วยการส่งสคริปต์และข้อมูลที่สำคัญโดยใช้ <link rel=preload>
นอกจากนี้ เราขอแนะนำให้ลองใช้รูปแบบต่างๆ เช่น PRPL เพื่อให้การนำทางครั้งแรกและครั้งต่อๆ ไปใช้งานได้ในทันที
![แผนภาพแสดงการแสดงผลฝั่งไคลเอ็นต์ที่ส่งผลต่อ FCP และ TTI](https://web.dev/static/articles/rendering-on-the-web/image/diagram-showing-client-si-42200b67e9867.png?authuser=6&hl=th)
ข้อเสียหลักในการแสดงผลฝั่งไคลเอ็นต์คือปริมาณ JavaScript ที่จำเป็นต้องใช้มีแนวโน้มที่จะเพิ่มขึ้นเมื่อแอปพลิเคชันเติบโตขึ้น ซึ่งอาจส่งผลต่อ INP ของหน้าเว็บ ซึ่งทำได้ยากขึ้นอย่างมากกับการเพิ่มไลบรารี JavaScript, Polyfill และโค้ดของบุคคลที่สามใหม่ๆ ที่แย่งชิงประสิทธิภาพในการประมวลผล และต้องมีการประมวลผลบ่อยครั้งก่อนที่เนื้อหาของหน้าเว็บจะแสดงได้
ประสบการณ์การใช้งานที่ใช้การแสดงผลฝั่งไคลเอ็นต์และอาศัยแพ็กเกจ JavaScript ขนาดใหญ่ควรพิจารณาการแยกโค้ดแบบเข้มงวดเพื่อลด TBT และ INP ระหว่างการโหลดหน้าเว็บ รวมถึงการใช้ JavaScript แบบ Lazy Loading เพื่อแสดงในสิ่งที่ผู้ใช้ต้องการเท่านั้น เมื่อจำเป็น สำหรับประสบการณ์ที่มีการโต้ตอบน้อยหรือไม่มีเลย การแสดงผลฝั่งเซิร์ฟเวอร์อาจเป็นโซลูชันที่ปรับขนาดได้มากขึ้นสำหรับปัญหาเหล่านี้
สำหรับผู้ที่สร้างแอปพลิเคชันหน้าเว็บเดียว การระบุส่วนสำคัญของอินเทอร์เฟซผู้ใช้ที่หน้าเว็บส่วนใหญ่แชร์จะช่วยให้คุณใช้เทคนิคการแคช Shell แอปพลิเคชัน เมื่อใช้ร่วมกับ Service Worker แล้ว ตัวเลือกนี้จะปรับปรุงประสิทธิภาพที่รับรู้ได้การเข้าชมซ้ำได้อย่างมาก เนื่องจากหน้าเว็บสามารถโหลด HTML ของ Application Shell และการอ้างอิงจาก CacheStorage
ได้อย่างรวดเร็ว
การ Rehydration รวมการแสดงผลฝั่งเซิร์ฟเวอร์และฝั่งไคลเอ็นต์เข้าด้วยกัน
Rehydration คือแนวทางที่พยายามที่จะแก้ไขข้อดีและข้อเสียระหว่างการแสดงผลฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์โดยใช้ทั้ง 2 แบบ คำขอการนำทาง เช่น การโหลดหน้าเว็บแบบเต็มหรือการโหลดซ้ำ จะได้รับการจัดการโดยเซิร์ฟเวอร์ที่แสดงผลแอปพลิเคชันเป็น HTML จากนั้น JavaScript และข้อมูลที่ใช้ในการแสดงผลจะถูกฝังลงในเอกสารผลลัพธ์ เมื่อทำอย่างรอบคอบแล้ว ก็จะทำให้ได้ FCP ที่รวดเร็วเหมือนการแสดงผลฝั่งเซิร์ฟเวอร์ จากนั้น "เลือก" โดยการแสดงผลอีกครั้งบนไคลเอ็นต์ นี่เป็นโซลูชันที่มีประสิทธิภาพ แต่ก็อาจมีข้อเสียด้านประสิทธิภาพอย่างมาก
ข้อเสียหลักของการแสดงผลฝั่งเซิร์ฟเวอร์ที่มีการรีไฮด์คืออาจส่งผลเชิงลบอย่างมากต่อ TBT และ INP แม้จะปรับปรุง FCP ก็ตาม หน้าที่แสดงผลฝั่งเซิร์ฟเวอร์อาจโหลดและโต้ตอบได้ แต่ตอบสนองต่ออินพุตไม่ได้จริงจนกว่าจะมีการเรียกใช้สคริปต์ฝั่งไคลเอ็นต์สำหรับคอมโพเนนต์และแนบตัวแฮนเดิลเหตุการณ์แล้ว บนอุปกรณ์เคลื่อนที่ ขั้นตอนนี้อาจใช้เวลาสักครู่ ผู้ใช้จึงเกิดความสับสนและหงุดหงิด
ปัญหาการขาดน้ำ: แอปเดียวแต่จ่ายราคาสองก้อน
เพื่อให้ JavaScript ฝั่งไคลเอ็นต์ "ดำเนินการ" จากจุดที่เซิร์ฟเวอร์ค้างไว้ได้อย่างถูกต้อง โดยไม่ต้องขอข้อมูลทั้งหมดที่เซิร์ฟเวอร์แสดงผล HTML อีกครั้ง โซลูชันการแสดงผลฝั่งเซิร์ฟเวอร์ส่วนใหญ่จะทำให้การตอบสนองเป็นอนุกรมการตอบสนองจากการอ้างอิงข้อมูลของ UI เป็นแท็กสคริปต์ในเอกสาร เนื่องจากการทำ HTML นี้ซ้ำจำนวนมาก การดึงน้ำจึงอาจก่อให้เกิดปัญหามากกว่าการโต้ตอบแบบล่าช้า
![เอกสาร HTML ที่มี UI อนุกรม ข้อมูลในบรรทัด และสคริปต์ Bundle.js](https://web.dev/static/articles/rendering-on-the-web/image/html-document-containing-94fb8c198eab8.png?authuser=6&hl=th)
เซิร์ฟเวอร์กำลังส่งคืนคำอธิบาย UI ของแอปพลิเคชันเพื่อตอบสนองต่อคำขอการนำทาง แต่เซิร์ฟเวอร์ยังส่งคืนข้อมูลแหล่งที่มาที่ใช้ในการเขียน UI ดังกล่าว และสำเนาที่สมบูรณ์ของการใช้งาน UI ซึ่งจะบูตขึ้นบนไคลเอ็นต์ UI จะไม่โต้ตอบจนกว่า bundle.js
จะโหลดและดำเนินการเสร็จสิ้น
เมตริกประสิทธิภาพที่รวบรวมจากเว็บไซต์จริงโดยใช้การแสดงผลฝั่งเซิร์ฟเวอร์และการจัดเรียงใหม่บ่งชี้ว่าตัวเลือกดังกล่าวไม่ใช่ตัวเลือกที่ดีที่สุด เหตุผลที่สำคัญที่สุดคือผลกระทบต่อประสบการณ์ของผู้ใช้ เมื่อหน้าเว็บดูพร้อมใช้งาน แต่ฟีเจอร์แบบอินเทอร์แอกทีฟไม่ทำงาน
![แผนภาพที่แสดงการแสดงผลของไคลเอ็นต์ซึ่งส่งผลเสียต่อ TTI](https://web.dev/static/articles/rendering-on-the-web/image/diagram-showing-client-re-be8ceca54b42e.png?authuser=6&hl=th)
แต่ก็มีความหวังว่าการแสดงผลฝั่งเซิร์ฟเวอร์ที่มีการรีไฮด์ ในระยะสั้น การใช้เพียงการแสดงผลฝั่งเซิร์ฟเวอร์สำหรับเนื้อหาแคชได้สูงเท่านั้นจะสามารถลด TTFB ได้ ซึ่งทำให้ได้ผลลัพธ์คล้ายกับการแสดงผลล่วงหน้า การเติมน้ำทีละน้อย ทีละน้อย หรือบางส่วนอาจเป็นกุญแจสำคัญที่จะทำให้เทคนิคนี้ใช้งานได้จริงมากขึ้นในอนาคต
สตรีมการแสดงผลฝั่งเซิร์ฟเวอร์และค่อยๆ เพิ่มความเร็ว
การแสดงผลฝั่งเซิร์ฟเวอร์มีการพัฒนาหลายอย่างในช่วงไม่กี่ปีที่ผ่านมา
การแสดงผลฝั่งเซิร์ฟเวอร์แบบสตรีมมิงช่วยให้คุณส่ง HTML เป็นชุดๆ ที่เบราว์เซอร์ค่อยๆ แสดงผลตามที่ได้รับได้ วิธีนี้จะช่วยให้ผู้ใช้ได้รับมาร์กอัปเร็วขึ้น ทำให้ FCP เร็วขึ้น ในปฏิกิริยา สตรีมที่ไม่พร้อมกันใน renderToPipeableStream()
เมื่อเทียบกับ renderToString()
แบบซิงโครนัสจะช่วยให้จัดการแรงดันย้อนกลับได้ดี
การทดแทนข้อมูลแบบโปรเกรสซีฟก็เช่นกัน ซึ่ง React ก็นำมาใช้ด้วย วิธีการนี้ทำให้แอปพลิเคชันที่แสดงผลบนเซิร์ฟเวอร์แต่ละชิ้นได้รับการ "บูต" เมื่อเวลาผ่านไป แทนที่จะเป็นวิธีการเริ่มต้นแอปพลิเคชันทั้งหมดพร้อมกันตามปกติในปัจจุบัน การทำเช่นนี้จะช่วยลดจำนวน JavaScript ที่จำเป็นในการทำให้หน้าเว็บมีการโต้ตอบได้ เนื่องจากจะทำให้คุณเลื่อนการอัปเกรดส่วนที่มีลำดับความสำคัญต่ำของฝั่งไคลเอ็นต์ออกไป เพื่อป้องกันไม่ให้หน้าเว็บบล็อกเทรดหลัก ซึ่งทำให้การโต้ตอบของผู้ใช้เกิดขึ้นได้เร็วขึ้นหลังจากที่ผู้ใช้เริ่มต้นการโต้ตอบดังกล่าว
การฟื้นฟูแบบโปรเกรสซีฟยังช่วยหลีกเลี่ยงข้อผิดพลาดที่พบบ่อยที่สุดอย่างหนึ่งในการเติมการแสดงผลฝั่งเซิร์ฟเวอร์ ซึ่งก็คือแผนผัง DOM ที่แสดงผลโดยเซิร์ฟเวอร์ถูกทำลายแล้วสร้างใหม่ทันที โดยส่วนใหญ่เป็นเพราะข้อมูลฝั่งไคลเอ็นต์แบบซิงโครนัสช่วงแรกที่แสดงผลจำเป็นต้องยังไม่พร้อม ซึ่งมักจะเป็น Promise
ที่ยังไม่ได้รับการแก้ไข
การคืนน้ำบางส่วน
การคืนน้ำบางส่วนพิสูจน์แล้วว่าทำได้ยาก วิธีนี้เป็นการขยายความต่อเนื่องของการเพิ่มความต่อเนื่องซึ่งจะวิเคราะห์แต่ละส่วนของหน้าเว็บ (คอมโพเนนต์ มุมมอง หรือต้นไม้) และระบุส่วนที่มีการโต้ตอบน้อยหรือไม่เกิดปฏิกิริยา สำหรับแต่ละส่วนที่มีการเปลี่ยนแปลงคงที่เหล่านี้ โค้ด JavaScript ที่เกี่ยวข้องจะเปลี่ยนรูปแบบเป็นการอ้างอิงแบบเฉื่อยและฟีเจอร์ตกแต่ง ซึ่งช่วยลดร่องรอยทางฝั่งลูกค้าให้เหลือเกือบ 0
วิธีการดื่มน้ำบางส่วนมาพร้อมกับปัญหาและความบกพร่องของตัวเอง ซึ่งก่อให้เกิดความท้าทายบางอย่างที่น่าสนใจสำหรับการแคช และการนำทางฝั่งไคลเอ็นต์ทำให้เราไม่สามารถสรุปได้ว่า HTML ที่แสดงผลโดยเซิร์ฟเวอร์สำหรับส่วนที่เฉื่อยชาของแอปพลิเคชันนั้นจะพร้อมใช้งานได้หากไม่มีการโหลดหน้าเว็บแบบเต็ม
การแสดงภาพแบบไตรโซมอร์ฟิก
หากโปรแกรมทำงานของบริการเป็นตัวเลือกสำหรับคุณ ให้ลองใช้การแสดงภาพแบบ Trisomorphic ซึ่งเป็นเทคนิคที่ให้คุณใช้การแสดงผลฝั่งเซิร์ฟเวอร์ของสตรีมสำหรับการนำทางครั้งแรกหรือที่ไม่ใช่ JS จากนั้นให้โปรแกรมทำงานของบริการแสดงผล HTML สำหรับการนำทางหลังจากที่ติดตั้งแล้ว ซึ่งจะช่วยให้คอมโพเนนต์และเทมเพลตที่แคชไว้เป็นปัจจุบันอยู่เสมอ และเปิดใช้การนำทางแบบ SPA สำหรับการแสดงผลมุมมองใหม่ๆ ในเซสชันเดียวกัน วิธีนี้ทำงานได้ดีที่สุดเมื่อคุณแชร์เทมเพลตและรหัสการกำหนดเส้นทางเดียวกันระหว่างเซิร์ฟเวอร์ หน้าไคลเอ็นต์ และ Service Worker ได้
![แผนภาพการแสดงภาพ Trisomorphic แสดงเบราว์เซอร์และ Service Worker ที่สื่อสารกับเซิร์ฟเวอร์](https://web.dev/static/articles/rendering-on-the-web/image/diagram-trisomorphic-ren-13fa9eea2e1a4.png?authuser=6&hl=th)
ข้อควรพิจารณาเกี่ยวกับ SEO
เมื่อเลือกกลยุทธ์การแสดงผลเว็บ ทีมต่างๆ มักคำนึงถึงผลกระทบของ SEO การแสดงผลฝั่งเซิร์ฟเวอร์เป็นตัวเลือกยอดนิยมสำหรับการส่งมอบประสบการณ์ที่ "สมบูรณ์แบบ" ที่โปรแกรมรวบรวมข้อมูลสามารถตีความได้ โปรแกรมรวบรวมข้อมูลเข้าใจ JavaScript ได้แต่มักจะมีข้อจำกัดเกี่ยวกับวิธีแสดงผล การแสดงผลฝั่งไคลเอ็นต์ใช้งานได้ แต่มักต้องมีการทดสอบและค่าใช้จ่ายเพิ่มเติม เมื่อไม่นานมานี้ การแสดงผลแบบไดนามิกได้กลายเป็นตัวเลือกที่ควรพิจารณาเช่นกันว่าสถาปัตยกรรมของคุณพึ่งพา JavaScript ฝั่งไคลเอ็นต์เป็นหลักหรือไม่
หากไม่แน่ใจ เครื่องมือทดสอบความเหมาะกับอุปกรณ์เคลื่อนที่เป็นวิธีที่ดีในการทดสอบว่าแนวทางที่คุณเลือกดำเนินการตามที่คุณคาดหวังหรือไม่ โดยจะแสดงให้เห็นภาพตัวอย่างของลักษณะที่หน้าปรากฏต่อ Crawler ของ Google, เนื้อหา HTML ที่ต่อเนื่องซึ่งพบหลังจากเรียกใช้ JavaScript และข้อผิดพลาดที่พบระหว่างการแสดงผล
![ภาพหน้าจอของ UI การทดสอบความเหมาะกับอุปกรณ์เคลื่อนที่](https://web.dev/static/articles/rendering-on-the-web/image/screenshot-the-mobile-fr-058e6aeec73c3.png?authuser=6&hl=th)
บทสรุป
เมื่อตัดสินใจเลือกวิธีแสดงผล ให้วัดและทำความเข้าใจว่าจุดคอขวดคืออะไร ลองพิจารณาว่าการแสดงผลแบบคงที่หรือการแสดงผลฝั่งเซิร์ฟเวอร์จะให้ทุกอย่างแก่คุณได้อย่างไร การส่ง HTML โดยใช้ JavaScript เพียงเล็กน้อยนั้นมักจะเพียงพอ เพื่อประสบการณ์แบบอินเทอร์แอกทีฟ นี่คืออินโฟกราฟิกที่มีประโยชน์ ซึ่งแสดงสเปกตรัมของเซิร์ฟเวอร์และไคลเอ็นต์
![อินโฟกราฟิกแสดงตัวเลือกต่างๆ ที่อธิบายไว้ในบทความนี้](https://web.dev/static/articles/rendering-on-the-web/image/app-rendering-types-examples.png?authuser=6&hl=th)
เครดิต
ขอขอบคุณทุกคนสำหรับรีวิวและแรงบันดาลใจ
Jeffrey Posnick, Houssein Djirdeh, Shubhie Panicker, Chris Harrelson และ Sebastian Markbåge