วิธีที่เราใช้การแยกโค้ด การแทรกโค้ด และการแสดงผลฝั่งเซิร์ฟเวอร์ใน PROXX
ที่งาน Google I/O 2019 เราได้เปิดตัว PROXX ซึ่งเป็นเกมทําลายเรือดำน้ำเวอร์ชันสมัยใหม่สำหรับเว็บ สิ่งที่ทำให้ PROXX แตกต่างก็คือการมุ่งเน้นที่การช่วยเหลือพิเศษ (คุณสามารถเล่นด้วยโปรแกรมอ่านหน้าจอได้) และความสามารถในการใช้งานบนฟีเจอร์โฟน เช่น บนอุปกรณ์เดสก์ท็อประดับไฮเอนด์ ฟีเจอร์โฟนมีข้อจำกัดหลายประการ ดังนี้
- CPU ที่ไม่มีประสิทธิภาพ
- GPU มีประสิทธิภาพต่ำหรือไม่มี
- หน้าจอขนาดเล็กที่ไม่มีการป้อนข้อมูลด้วยการสัมผัส
- หน่วยความจํามีจํานวนจำกัดมาก
แต่อุปกรณ์เหล่านี้ใช้เบราว์เซอร์ที่ทันสมัยและราคาไม่แพง ด้วยเหตุนี้ โทรศัพท์ฟีเจอร์จึงกลับมาได้รับความนิยมอีกครั้งในตลาดเกิดใหม่ ระดับราคานี้ช่วยให้กลุ่มเป้าหมายใหม่ทั้งหมดที่ก่อนหน้านี้ซื้ออุปกรณ์ราคาแพงไม่ได้ได้เข้ามาออนไลน์และใช้เว็บสมัยใหม่ ในปี 2019 มีการคาดการณ์ว่าจะมียอดขายฟีเจอร์โฟนประมาณ 400 ล้านเครื่องในอินเดียเพียงประเทศเดียว ดังนั้นผู้ใช้ฟีเจอร์โฟนจึงอาจกลายเป็นกลุ่มเป้าหมายที่สำคัญของคุณ นอกจากนี้ ความเร็วในการเชื่อมต่อยังคล้ายกับ 2G และเป็นกฎพื้นฐานในตลาดเกิดใหม่ด้วย เราทําอย่างไรให้ PROXX ทํางานได้ดีภายใต้เงื่อนไขของโทรศัพท์ฟีเจอร์
ประสิทธิภาพเป็นสิ่งสำคัญ ซึ่งรวมถึงทั้งประสิทธิภาพการโหลดและประสิทธิภาพรันไทม์ การศึกษาพบว่าประสิทธิภาพที่ดีสัมพันธ์กับการคงผู้ใช้ไว้มากขึ้น เพิ่ม Conversion และที่สำคัญที่สุดคือความครอบคลุมที่มากขึ้น Jeremy Wagner มีข้อมูลและข้อมูลเชิงลึกอีกมากมายเกี่ยวกับเหตุผลที่ประสิทธิภาพสำคัญ
นี่คือส่วนที่ 1 ของชุดข้อมูลที่ประกอบด้วย 2 ส่วน ส่วนที่ 1 จะเน้นที่ประสิทธิภาพการโหลด ส่วนส่วนที่ 2 จะเน้นที่ประสิทธิภาพรันไทม์
การบันทึกสถานการณ์ปัจจุบัน
การทดสอบประสิทธิภาพการโหลดในอุปกรณ์จริงเป็นสิ่งสําคัญ หากคุณไม่มีอุปกรณ์จริงอยู่กับตัว เราขอแนะนำให้ใช้ WebPageTest โดยเฉพาะการตั้งค่า "แบบง่าย" WPT จะทำการทดสอบการโหลดจำนวนมากในอุปกรณ์จริงที่มีการเชื่อมต่อ 3G จำลอง
3G เป็นความเร็วที่เหมาะสําหรับการวัด แม้ว่าคุณอาจคุ้นเคยกับ 4G, LTE หรืออีกไม่นานก็ 5G แต่อินเทอร์เน็ตบนอุปกรณ์เคลื่อนที่กลับมีสภาพที่แตกต่างออกไป คุณอาจอยู่บนรถไฟ ในการประชุม คอนเสิร์ต หรือบนเครื่องบิน ประสบการณ์การใช้งานที่คุณจะได้รับมีแนวโน้มที่จะใกล้เคียงกับ 3G และบางครั้งอาจแย่กว่านั้น
อย่างไรก็ตาม เราจะมุ่งเน้นที่ 2G ในบทความนี้ เนื่องจาก PROXX กําหนดเป้าหมายไปยังฟีเจอร์โฟนและตลาดเกิดใหม่ในกลุ่มเป้าหมายอย่างชัดเจน เมื่อ WebPageTest ทำการทดสอบแล้ว คุณจะเห็น Waterfall (คล้ายกับที่คุณเห็นในเครื่องมือสำหรับนักพัฒนาเว็บ) และแถบฟิล์มที่ด้านบน แถบแสดงตัวอย่างภาพจะแสดงสิ่งที่ผู้ใช้เห็นขณะที่แอปโหลด ใน 2G ประสบการณ์การโหลดของ PROXX เวอร์ชันที่ไม่ได้เพิ่มประสิทธิภาพนั้นค่อนข้างแย่
เมื่อโหลดผ่าน 3G ผู้ใช้จะเห็นเพียงสีขาวเป็นเวลา 4 วินาที เมื่อใช้ 2G ผู้ใช้จะไม่เห็นอะไรเลยนานกว่า 8 วินาที หากคุณอ่านเหตุผลที่ประสิทธิภาพสำคัญ คุณจะทราบว่าตอนนี้เราเสียผู้ใช้ที่มีศักยภาพจำนวนมากไปเนื่องจากความอดทนต่ำ ผู้ใช้ต้องดาวน์โหลด JavaScript ทั้งหมดขนาด 62 KB เพื่อให้ทุกอย่างปรากฏบนหน้าจอ ข้อดีของสถานการณ์นี้คือ เมื่อทุกอย่างปรากฏบนหน้าจอในครั้งที่ 2 ทุกอย่างจะโต้ตอบได้ด้วย หรืออาจจะยังมีหวังอยู่กันแน่นะ
หลังจากดาวน์โหลด JS ที่บีบอัดด้วย gzip ประมาณ 62 KB และสร้าง DOM แล้ว ผู้ใช้จะเห็นแอปของเรา แอปเป็นแบบอินเทอร์แอกทีฟในทางเทคนิค อย่างไรก็ตาม เมื่อดูภาพแล้ว ความจริงกลับแตกต่างออกไป เว็บแบบอักษรจะยังคงโหลดอยู่เบื้องหลัง และผู้ใช้จะไม่เห็นข้อความจนกว่าแบบอักษรจะพร้อมใช้งาน แม้ว่าสถานะนี้จะมีคุณสมบัติตรงตามFirst Meaningful Paint (FMP) แต่ก็ไม่มีคุณสมบัติตรงตามการโต้ตอบอย่างเหมาะสม เนื่องจากผู้ใช้ไม่สามารถบอกได้ว่าอินพุตใดหมายถึงอะไร จากนั้นแอปจะใช้เวลาอีก 1 วินาทีใน 3G และ 3 วินาทีใน 2G จึงจะพร้อมใช้งาน โดยรวมแล้ว แอปจะใช้เวลา 6 วินาทีใน 3G และ 11 วินาทีใน 2G จึงจะโต้ตอบได้
การวิเคราะห์ Waterfall
เมื่อทราบสิ่งที่ผู้ใช้เห็นแล้ว เราจะต้องหาสาเหตุ ในกรณีนี้ เราสามารถดู Waterfall และวิเคราะห์สาเหตุที่ทรัพยากรโหลดช้าเกินไป ในร่องรอย 2G สําหรับ PROXX เราพบสัญญาณอันตรายหลัก 2 อย่าง ได้แก่
- มีเส้นบางๆ หลายเส้นหลากสี
- ไฟล์ JavaScript ประกอบกันเป็นเชน ตัวอย่างเช่น ทรัพยากรที่ 2 จะเริ่มโหลดก็ต่อเมื่อทรัพยากรที่ 1 โหลดเสร็จแล้ว และทรัพยากรที่ 3 จะเริ่มโหลดก็ต่อเมื่อทรัพยากรที่ 2 โหลดเสร็จแล้ว
การลดจํานวนการเชื่อมต่อ
เส้นบางๆ แต่ละเส้น (dns
, connect
, ssl
) แสดงถึงการสร้างการเชื่อมต่อ HTTP ใหม่ การตั้งค่าการเชื่อมต่อใหม่มีค่าใช้จ่ายสูงเนื่องจากใช้ 3G ประมาณ 1 วินาที และประมาณ 2.5 วินาทีเมื่อใช้ 2G ในการแสดงโฆษณาสื่อกลางตามลำดับขั้น เราเห็นการเชื่อมต่อใหม่สำหรับรายการต่อไปนี้
- คําขอ #1:
index.html
- คําขอ #5: รูปแบบแบบอักษรจาก
fonts.googleapis.com
- คําขอ #8: Google Analytics
- คําขอ #9: ไฟล์แบบอักษรจาก
fonts.gstatic.com
- คำขอ #14: ไฟล์ Manifest ของเว็บแอป
การเชื่อมต่อใหม่สำหรับ index.html
เป็นสิ่งที่หลีกเลี่ยงไม่ได้ โดยเบราว์เซอร์ต้องสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ของเราเพื่อรับเนื้อหา คุณหลีกเลี่ยงการเชื่อมต่อใหม่สําหรับ Google Analytics ได้โดยการแทรกโค้ดอย่าง Minimal Analytics แต่ Google Analytics ไม่ได้บล็อกไม่ให้แอปแสดงผลหรือโต้ตอบ เราจึงไม่ได้สนใจความเร็วในการโหลดมากนัก ตามหลักการแล้ว Google Analytics ควรโหลดขึ้นมาในเวลาที่ไม่มีความเคลื่อนไหว เมื่อโหลดทุกอย่างไปแล้ว วิธีนี้จะช่วยประหยัดแบนด์วิดท์หรือกำลังการประมวลผลในระหว่างการโหลดครั้งแรก การเชื่อมต่อใหม่สำหรับไฟล์ Manifest ของเว็บแอปเป็นไปตามข้อกำหนดการดึงข้อมูล เนื่องจากต้องโหลดไฟล์ Manifest ผ่านการเชื่อมต่อที่ไม่มีข้อมูลเข้าสู่ระบบ เราขอย้ำว่าไฟล์ Manifest ของเว็บแอปไม่ได้บล็อกไม่ให้แอปแสดงผลหรือเป็นแบบอินเทอร์แอกทีฟ เราจึงไม่ต้องกังวลมากนัก
อย่างไรก็ตาม ฟอนต์ 2 รายการและสไตล์ของฟอนต์เป็นปัญหาเนื่องจากบล็อกการแสดงผลและการโต้ตอบ เมื่อดู CSS ที่ fonts.googleapis.com
ส่งมา พบว่ามีกฎ @font-face
เพียง 2 กฎสําหรับแบบอักษรแต่ละแบบ สไตล์แบบอักษรมีขนาดเล็กมาก เราจึงตัดสินใจแทรกไว้ใน HTML เพื่อตัดการเชื่อมต่อที่ไม่จำเป็นออก 1 รายการ หากต้องการหลีกเลี่ยงค่าใช้จ่ายในการตั้งค่าการเชื่อมต่อสำหรับไฟล์แบบอักษร เราคัดลอกไฟล์เหล่านั้นไปยังเซิร์ฟเวอร์ของเราเองได้
การโหลดแบบขนาน
เมื่อดู Waterfall เราจะเห็นว่าเมื่อโหลดไฟล์ JavaScript ไฟล์แรกเสร็จแล้ว ไฟล์ใหม่ก็เริ่มโหลดทันที ซึ่งมักเป็นกรณีของข้อกําหนดของโมดูล โมดูลหลักของเราอาจมีการนำเข้าแบบคงที่ ดังนั้น JavaScript จึงไม่สามารถทำงานได้จนกว่าจะโหลดการนําเข้าเหล่านั้น สิ่งสำคัญที่ควรทราบคือทรัพยากร Dependency เหล่านี้จะได้รับการทราบในเวลาสร้าง เราสามารถใช้แท็ก <link rel="preload">
เพื่อให้แน่ใจว่า Dependency ทั้งหมดจะเริ่มโหลดทันทีที่เราได้รับ HTML
ผลลัพธ์
มาดูกันว่าการเปลี่ยนแปลงของเราบรรลุเป้าหมายอะไรบ้าง คุณต้องไม่เปลี่ยนตัวแปรอื่นใดในการตั้งค่าการทดสอบที่อาจทำให้ผลลัพธ์บิดเบือน เราจึงจะใช้การตั้งค่าอย่างง่ายของ WebPageTest สำหรับส่วนที่เหลือของบทความนี้และดูแถบแสดงผู้เข้าร่วม
การเปลี่ยนแปลงเหล่านี้ลด TTI จาก 11 เป็น 8.5 ซึ่งเท่ากับเวลาโดยประมาณในการตั้งค่าการเชื่อมต่อ 2.5 วินาทีที่เราตั้งใจว่าจะนำออก เยี่ยมไปเลย
การแสดงผลล่วงหน้า
แม้ว่าเราจะเพิ่งลด TTI แต่ก็ไม่ได้ส่งผลกระทบต่อหน้าจอสีขาวที่ยาวนานซึ่งผู้ใช้ต้องทนดูเป็นเวลา 8.5 วินาที การส่งมาร์กอัปที่มีการจัดรูปแบบใน index.html
อาจเป็นการปรับปรุงที่ใหญ่ที่สุดสำหรับ FMP เทคนิคทั่วไปที่ทำได้คือการแสดงผลล่วงหน้าและการแสดงผลฝั่งเซิร์ฟเวอร์ ซึ่งมีความเกี่ยวข้องกันมากและมีคำอธิบายอยู่ในการแสดงผลบนเว็บ เทคนิคทั้งสองนี้จะเรียกใช้เว็บแอปในโหนดและจัดลำดับ DOM ที่ได้ให้เป็น HTML การแสดงผลฝั่งเซิร์ฟเวอร์จะดำเนินการนี้ตามคำขอฝั่งเซิร์ฟเวอร์ ส่วนการแสดงผลล่วงหน้าจะดำเนินการนี้เมื่อสร้างและจัดเก็บเอาต์พุตเป็น index.html
ใหม่ เนื่องจาก PROXX เป็นแอป JAMStack และไม่มีฝั่งเซิร์ฟเวอร์ เราจึงตัดสินใจใช้การแสดงผลล่วงหน้า
การใช้โปรแกรมแสดงผลล่วงหน้าทำได้หลายวิธี ใน PROXX เราเลือกที่จะใช้ Puppeteer ซึ่งจะเปิด Chrome โดยไม่แสดง UI และให้คุณควบคุมอินสแตนซ์นั้นจากระยะไกลด้วย Node API ได้ เราใช้วิธีนี้เพื่อแทรกมาร์กอัปและ JavaScript จากนั้นอ่าน DOM กลับเป็นสตริง HTML เนื่องจากเราใช้ CSS Modules เราจึงได้รับ CSS แทรกในบรรทัดของสไตล์ที่ต้องการได้แบบไม่มีค่าใช้จ่าย
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(rawIndexHTML);
await page.evaluate(codeToRun);
const renderedHTML = await page.content();
browser.close();
await writeFile("index.html", renderedHTML);
เมื่อใช้ฟีเจอร์นี้ เราคาดว่า FMP จะมีประสิทธิภาพดีขึ้น เรายังคงต้องโหลดและเรียกใช้ JavaScript ในจํานวนเท่าเดิมกับก่อนหน้านี้ จึงไม่น่าที่ TTI จะเปลี่ยนแปลงมากนัก index.html
ของเรามีขนาดใหญ่ขึ้นและอาจทำให้ TTI ล่าช้าออกไปเล็กน้อย วิธีเดียวที่จะทราบคือเรียกใช้ WebPageTest
การแสดงผลที่มีความหมายครั้งแรกลดลงจาก 8.5 วินาทีเป็น 4.9 วินาที ซึ่งเป็นการปรับปรุงที่ดีมาก TTI ของเรายังคงอยู่ที่ประมาณ 8.5 วินาที จึงแทบไม่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ สิ่งที่เราทําคือการเปลี่ยนแปลงการรับรู้ บางคนอาจเรียกว่าเป็นการแสดงมายากล การเรนเดอร์ภาพระดับกลางของเกมจะช่วยปรับปรุงประสิทธิภาพการโหลดที่ผู้ใช้รับรู้ให้ดียิ่งขึ้น
การฝัง
เมตริกอีกรายการที่ทั้ง DevTools และ WebPageTest แสดงให้เราเห็นคือ Time To First Byte (TTFB) คือเวลาที่ใช้ในการส่งไบต์แรกของคําขอไปจนถึงการรับไบต์แรกของคําตอบ เวลานี้มักเรียกว่า Round Trip Time (RTT) ด้วย แม้ว่าในทางเทคนิคแล้วตัวเลข 2 ตัวนี้จะแตกต่างกัน โดย RTT จะไม่รวมเวลาประมวลผลคําขอฝั่งเซิร์ฟเวอร์ เครื่องมือสำหรับนักพัฒนาเว็บและ WebPageTest จะแสดงภาพ TTFB ด้วยสีอ่อนภายในบล็อกคำขอ/การตอบกลับ
เมื่อดูที่ Waterfall แล้ว เราพบว่าคำขอทั้งหมดใช้เวลาส่วนใหญ่ในการรอไบต์แรก
ปัญหานี้เป็นสิ่งที่ HTTP/2 Push สร้างขึ้นเพื่อแก้ปัญหาตั้งแต่แรก นักพัฒนาแอปทราบว่าต้องใช้ทรัพยากรบางอย่างและสามารถส่งทรัพยากรเหล่านั้นได้ เมื่อไคลเอ็นต์ทราบว่าต้องดึงข้อมูลอื่นๆ เพิ่มเติม ข้อมูลเหล่านั้นจะอยู่ในแคชของเบราว์เซอร์อยู่แล้ว ปรากฏว่า Push ของ HTTP/2 นั้นใช้งานยากเกินไปและเราไม่แนะนำให้ใช้ เราจะกลับมาพิจารณาปัญหานี้อีกครั้งในระหว่างการกำหนดมาตรฐาน HTTP/3 ในตอนนี้ วิธีแก้ไขที่ง่ายที่สุดคือแทรกทรัพยากรที่สำคัญทั้งหมดโดยลดทอนประสิทธิภาพในการแคช
CSS ที่สําคัญของเราแทรกอยู่ในหน้าเว็บอยู่แล้วด้วยโมดูล CSS และโปรแกรมแสดงผลก่อนโหลดที่ใช้ Puppeteer สำหรับ JavaScript เราต้องแทรกโมดูลที่สำคัญและโมดูลที่ต้องพึ่งพาในหน้า งานนี้มีระดับความยากง่ายแตกต่างกันไป โดยขึ้นอยู่กับเครื่องมือจัดกลุ่มที่คุณใช้
ซึ่งทำให้ TTI ลดลง 1 วินาที ตอนนี้เรามาถึงจุดที่ index.html
ของเรามีทุกอย่างที่จำเป็นสำหรับการแสดงผลครั้งแรกและกลายเป็นแบบอินเทอร์แอกทีฟแล้ว HTML สามารถแสดงผลได้ขณะที่ยังดาวน์โหลดอยู่ ซึ่งจะเป็นการสร้าง FMP ของเรา เมื่อ HTML แยกวิเคราะห์และดำเนินการเสร็จแล้ว แอปจะโต้ตอบได้
การแยกโค้ดอย่างหนัก
ใช่ index.html
ของเรามีทุกอย่างที่จำเป็นต่อการสร้างการโต้ตอบ แต่จากการตรวจสอบอย่างละเอียดกลับพบว่ามีทุกอย่างอยู่ในนั้นด้วย index.html
ของเรามีขนาดประมาณ 43 KB เรามาลองพิจารณาถึงสิ่งที่ผู้ใช้สามารถโต้ตอบด้วยได้ตั้งแต่เริ่มต้น เรามีแบบฟอร์มสำหรับกำหนดค่าเกมที่ประกอบด้วยองค์ประกอบ 2 อย่าง ปุ่มเริ่มต้น และอาจโค้ดบางอย่างเพื่อคงการทำงานและโหลดการตั้งค่าผู้ใช้ เท่านี้แหละ 43 KB ดูเหมือนว่าจะมีขนาดใหญ่
หากต้องการทำความเข้าใจที่มาของขนาดแพ็กเกจ เราสามารถใช้ Source Map Explorer หรือเครื่องมือที่คล้ายกันเพื่อแจกแจงองค์ประกอบของแพ็กเกจ ตามที่ได้คาดไว้ แพ็กเกจของเรามีตรรกะเกม เครื่องมือแสดงผล หน้าจอชนะ หน้าจอแพ้ และยูทิลิตีต่างๆ หน้า Landing Page ต้องใช้โมดูลเหล่านี้เพียงส่วนเล็กๆ เท่านั้น การย้ายทุกอย่างที่ไม่จําเป็นต่อการทำงานแบบอินเทอร์แอกทีฟไปยังโมดูลที่โหลดแบบเลื่อนเวลาไว้จะลด TTI อย่างมาก
สิ่งที่เราต้องทําคือแยกโค้ด การแยกโค้ดจะแยกกลุ่มที่รวมทุกอย่างไว้ด้วยกันออกเป็นส่วนเล็กๆ ที่โหลดแบบ Lazy Loading ได้เมื่อต้องการ Bundler ยอดนิยมอย่าง Webpack, Rollup และ Parcel รองรับการแยกโค้ดโดยใช้ import()
แบบไดนามิก เครื่องมือจะวิเคราะห์โค้ดและแทรกโมดูลทั้งหมดที่นําเข้าแบบคงที่ ทุกอย่างที่คุณนําเข้าแบบไดนามิกจะใส่ไว้ในไฟล์ของตัวเองและจะดึงข้อมูลจากเครือข่ายก็ต่อเมื่อมีการเรียกใช้ import()
แน่นอนว่าการเข้าร่วมเครือข่ายมีค่าใช้จ่ายและควรทำเฉพาะในกรณีที่คุณมีเวลาว่าง หลักการคือนําเข้าโมดูลที่จําเป็นอย่างยิ่งแบบคงที่ ณ เวลาโหลด และโหลดทุกอย่างที่เหลือแบบไดนามิก แต่คุณไม่ควรรอจนวินาทีสุดท้ายเพื่อโหลดโมดูลแบบ Lazy Load ที่แน่นอนว่าจะใช้ Idle Until Urgent ของ Phil Walton เป็นรูปแบบที่ยอดเยี่ยมสำหรับแนวทางกลางๆ ที่สมเหตุสมผลระหว่างการโหลดแบบ Lazy Loading กับการโหลดอย่างเต็มรูปแบบ
ใน PROXX เราได้สร้างไฟล์ lazy.js
ที่นําเข้าแบบคงที่ทุกอย่างที่เราไม่ต้องการ ในไฟล์หลัก เราสามารถนําเข้า lazy.js
แบบไดนามิก อย่างไรก็ตาม คอมโพเนนต์ Preact บางรายการของเราไปอยู่ใน lazy.js
ซึ่งทำให้เกิดความซับซ้อนเล็กน้อยเนื่องจาก Preact จัดการคอมโพเนนต์ที่โหลดแบบเลื่อนเวลาไว้ล่วงหน้าไม่ได้ ด้วยเหตุนี้ เราจึงเขียน Wrapper ของคอมโพเนนต์ deferred
สั้นๆ ที่ช่วยให้เราแสดงผลตัวยึดตำแหน่งได้จนกว่าคอมโพเนนต์จริงจะโหลดขึ้นมา
export default function deferred(componentPromise) {
return class Deferred extends Component {
constructor(props) {
super(props);
this.state = {
LoadedComponent: undefined
};
componentPromise.then(component => {
this.setState({ LoadedComponent: component });
});
}
render({ loaded, loading }, { LoadedComponent }) {
if (LoadedComponent) {
return loaded(LoadedComponent);
}
return loading();
}
};
}
เมื่อดำเนินการเสร็จแล้ว เราจะใช้ Promise ของคอมโพเนนต์ในฟังก์ชัน render()
ได้ ตัวอย่างเช่น คอมโพเนนต์ <Nebula>
ที่แสดงภาพพื้นหลังแบบเคลื่อนไหวจะถูกแทนที่ด้วย <div>
ที่ว่างเปล่าระหว่างที่คอมโพเนนต์กำลังโหลด เมื่อโหลดคอมโพเนนต์และพร้อมใช้งานแล้ว <div>
จะถูกแทนที่ด้วยคอมโพเนนต์จริง
const NebulaDeferred = deferred(
import("/components/nebula").then(m => m.default)
);
return (
// ...
<NebulaDeferred
loading={() => <div />}
loaded={Nebula => <Nebula />}
/>
);
เมื่อทำสิ่งเหล่านี้แล้ว เราลด index.html
เหลือเพียง 20 KB ซึ่งน้อยกว่าครึ่งหนึ่งของขนาดเดิม การดำเนินการนี้ส่งผลต่อ FMP และ TTI อย่างไร WebPageTest ช่วยบอกได้
FMP และ TTI ของเราห่างกันเพียง 100 มิลลิวินาที เนื่องจากเป็นเพียงการแยกวิเคราะห์และเรียกใช้ JavaScript ที่ฝังไว้ หลังจากผ่านไปเพียง 5.4 วินาทีบน 2G แอปก็โต้ตอบได้อย่างเต็มที่ ส่วนโมดูลอื่นๆ ทั้งหมดที่ไม่จำเป็นต้องมีการโหลดในเบื้องหลัง
เทคนิคแพรวพราวเพิ่มเติม
หากดูรายการข้อบังคับที่สำคัญด้านบน คุณจะเห็นว่าเครื่องมือแสดงผลไม่ได้อยู่ในข้อบังคับที่สำคัญ แน่นอนว่าเกมจะยังไม่เริ่มจนกว่าเราจะมีเครื่องมือแสดงผลเพื่อแสดงผลเกม เราปิดใช้ปุ่ม "เริ่ม" ได้จนกว่าเครื่องมือแสดงผลจะพร้อมเริ่มเกม แต่จากประสบการณ์ของเรา ผู้ใช้มักจะใช้เวลาในการกำหนดการตั้งค่าเกมนานพอที่จะไม่จําเป็นต้องปิดใช้ปุ่มดังกล่าว ส่วนใหญ่แล้ว เครื่องมือแสดงผลและโมดูลอื่นๆ ที่เหลือจะโหลดเสร็จสิ้นก่อนที่ผู้ใช้จะกด "เริ่ม" ในกรณีที่ไม่ค่อยเกิดขึ้นบ่อยนักที่ผู้ใช้ดำเนินการเร็วกว่าการเชื่อมต่อเครือข่าย เราจะแสดงหน้าจอการโหลดแบบง่ายที่รอให้โมดูลที่เหลือดำเนินการเสร็จ
บทสรุป
การวัดผลมีความสําคัญ เราขอแนะนําให้วัดผลก่อนใช้งานการเพิ่มประสิทธิภาพเสมอ เพื่อหลีกเลี่ยงการเสียเวลาไปกับปัญหาที่ไม่ได้เกิดขึ้นจริง นอกจากนี้ ควรทำการวัดในอุปกรณ์จริงที่ใช้การเชื่อมต่อ 3G หรือ WebPageTest หากไม่มีอุปกรณ์จริงอยู่ในมือ
แถบแสดงตัวอย่างภาพจะให้ข้อมูลเชิงลึกเกี่ยวกับความรู้สึกของผู้ใช้ขณะโหลดแอป Waterfall ช่วยบอกได้ว่าทรัพยากรใดเป็นสาเหตุที่อาจทําให้ใช้เวลาโหลดนาน ต่อไปนี้คือรายการตรวจสอบสิ่งที่คุณทำได้เพื่อปรับปรุงประสิทธิภาพในการโหลด
- ส่งชิ้นงานให้ได้มากที่สุดผ่านการเชื่อมต่อเดียว
- การโหลดล่วงหน้าหรือแม้แต่ทรัพยากรในบรรทัดที่ต้องใช้ในการแสดงผลครั้งแรกและการโต้ตอบ
- แสดงผลแอปล่วงหน้าเพื่อปรับปรุงประสิทธิภาพการโหลดที่รับรู้
- ใช้การแยกโค้ดอย่างหนักเพื่อลดจํานวนโค้ดที่จําเป็นสําหรับการโต้ตอบ
โปรดติดตามส่วน 2 ซึ่งเราจะพูดถึงวิธีเพิ่มประสิทธิภาพรันไทม์ในอุปกรณ์ที่มีข้อจำกัดสูง