Expo Router เผชิญปัญหาคอขวดที่ความลึก 42 เส้นทางซ้อน
การทดสอบประสิทธิภาพ Expo Router เผยเฟรมเรตตกเหลือ 38fps และแรมพุ่ง 140MB บนแอนดรอยด์เมื่อความลึกสะสมถึง 42 ระดับ

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
- การย้ายแดชบอร์ดมัลติเทแนนต์จาก React Navigation สู่ Expo Router พบปัญหาที่ 42 เส้นทางซ้อน
- แอนดรอยด์ระดับกลางแรมพุ่งขึ้น 140MB และเฟรมเรตตกจาก 60fps เหลือ 38fps
- ฮุก useSegments() ทำให้เลย์เอาต์ทรีทั้งหมดเรนเดอร์ใหม่ทุกครั้งที่มีการนำทาง
- การแก้ทำได้โดยแปลงสไตล์ TailwindCSS ให้เป็นสแตติกสไตล์ชีทแทนคลาสไดนามิก
เมื่อทีมพัฒนาทำการย้ายระบบแดชบอร์ดแบบมัลติเทแนนต์จาก React Navigation ไปสู่ระบบการนำทางแบบอาศัยไฟล์ของ Expo Router พวกเขาพบกับจุดสะดุดด้านประสิทธิภาพอย่างเงียบ ๆ เมื่อความลึกของเส้นทางซ้อนกันถึง 42 ระดับ ส่งผลให้แอนิเมชันการนำทางตกลงจาก 60 เฟรมต่อวินาที (fps) เหลือเพียง 38 fps และปริมาณการใช้หน่วยความจำพุ่งสูงขึ้นถึง 140 เมกะไบต์ (MB) บนอุปกรณ์แอนดรอยด์ระดับกลาง ซึ่งการทดสอบเบนช์มาร์กครั้งนี้จัดทำขึ้นเพื่อเจาะลึกหาจุดแตกหักดังกล่าว
โครงสร้างไดเรกทอรีตัวอย่างประกอบด้วย:
- app/ (auth)/ login.tsx
- (dashboard)/ _layout.tsx index.tsx [tenant]/ settings/ [section]/ [subsection]/ index.tsx (ความลึกเทียบเท่า 6 เลเวล)
ผลการเปรียบเทียบตัวชี้วัดประสิทธิภาพตามความลึกของเส้นทางมีดังนี้:
- ระดับ 10 เส้นทาง: เวลาเฉลี่ยในการนำทาง 68 มิลลิวินาที, หน่วยความจำเพิ่มขึ้น +22 MB, เฟรมดรอป 0 ครั้ง, ซีพียู UI Thread ใช้ไป 14%
- ระดับ 25 เส้นทาง: เวลาเฉลี่ยในการนำทาง 105 มิลลิวินาที, หน่วยความจำเพิ่มขึ้น +58 MB, เฟรมดรอป 2 ครั้ง, ซีพียู UI Thread ใช้ไป 28%
- ระดับ 50 เส้นทาง: เวลาเฉลี่ยในการนำทาง 187 มิลลิวินาที, หน่วยความจำเพิ่มขึ้น +142 MB, เฟรมดรอป 9 ครั้ง, ซีพียู UI Thread ใช้ไป 51%
- ระดับ 75 เส้นทาง: เวลาเฉลี่ยในการนำทาง 312 มิลลิวินาที, หน่วยความจำเพิ่มขึ้น +229 MB, เฟรมดรอป 18 ครั้ง, ซีพียู UI Thread ใช้ไป 73%
สาเหตุหลักของปัญหามาจากฮุก useSegments() ของ Expo Router ที่บังคับให้เรนเดอร์โครงสร้างเลย์เอาต์ทั้งหมดใหม่ในทุกเหตุการณ์การนำทาง เมื่อจำนวนเส้นทางเกิน 50 เส้นทาง ต้นทุนการประมวลผลการคืนดี (reconciliation) จะรวมตัวเข้ากับการคำนวณคลาส TailwindCSS ซ้ำในคอมโพเนนต์ _layout.tsx ที่ซ้อนกันอยู่

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
การวิเคราะห์เชิงลึกระบุว่า ปัญหาลักษณะนี้มักเกิดขึ้นบ่อยในสถาปัตยกรรมแอปพลิเคชันสมัยใหม่ที่พึ่งพาการจัดการสถานะเชิงเส้นทาง (File-based routing) โดยเมื่อความลึกของสแต็กเพิ่มขึ้น ต้นทุนการส่งผ่านข้อมูลผ่านบริดจ์เนทีฟและการคำนวณสไตล์แบบไดนามิกจะกลายเป็นคอขวดสำคัญที่นักพัฒนาต้องระมัดระวังในการออกแบบโครงสร้างโปรเจกต์ขนาดใหญ่
จุดเปลี่ยนสำคัญในการแก้ปัญหาคือการแยกยูทิลิตี้ของ TailwindCSS ออกมาเป็นการอ้างอิงสไตล์ชีทแบบสแตติก แทนที่จะใช้พร็อพ className แบบไดนามิกในเลย์เอาต์ที่มีการซ้อนกันหลายชั้น นอกจากนี้ เลย์เอาต์แบบ (tabs) ของ Expo Router ยังกระตุ้นให้เกิดการเรนเดอร์ใหม่เมื่อผู้ใช้สลับระหว่างหน้าแท็บ การใช้ CSS container queries จึงช่วยจำกัดขอบเขตแอนิเมชันของตัวบ่งชี้แท็บและป้องกันอาการเลย์เอาต์กระตุกได้
ในส่วนของความสามารถในการเข้าถึง (Accessibility) สแต็กการนำทางที่ลึกมากเกินไปได้ส่งผลกระทบต่อการโฟกัสของโปรแกรมอ่านหน้าจอเมื่อหน้าจอโมดอลทับซ้อนกับตัวนำทางแบบแท็บ เนื่องจากแท็ก <Slot /> ไม่ส่งต่อคุณสมบัติ accessibilityViewIsModal ไปยังหน้าจอลูกข่าย จุดตัดที่ 50 เส้นทางจึงไม่ใช่เรื่องบังเอิญ แต่เป็นจุดที่ขนาดของบันเดิล JavaScript ตัดกับต้นทุนการซีเรียลไลซ์ชันบนบริดจ์เนทีฟ ซึ่งต่ำกว่าจุดนั้นประโยชน์ด้านประสบการณ์นักพัฒนาของ Expo Router ยังคงคุ้มค่ากว่าภาระด้านประสิทธิภาพ
ที่มา: Dev.to
พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้
ความคิดเห็น
แสดงความคิดเห็น