การเพิ่มประสิทธิภาพ JavaScript สำหรับสตาร์ทอัพ

เมื่อเราสร้างเว็บไซต์ที่อาศัย JavaScript มากขึ้น บางครั้งเราก็ต้องจ่ายค่าสิ่งที่ส่งไปในรูปแบบที่เราไม่สามารถมองเห็นได้ง่ายๆ ในบทความนี้ เราจะอธิบายว่าความมีระเบียบวินัยเล็กน้อยจะช่วยได้อย่างไรหากคุณต้องการให้เว็บไซต์โหลดและโต้ตอบได้อย่างรวดเร็วบนอุปกรณ์เคลื่อนที่ การส่ง JavaScript น้อยลงอาจทำให้เวลาในการรับส่งข้อมูลในเครือข่ายลดลง ใช้เวลาในการบีบอัดโค้ดน้อยลง และใช้เวลาในการแยกวิเคราะห์และคอมไพล์ JavaScript น้อยลง

เครือข่าย

เมื่อนักพัฒนาซอฟต์แวร์ส่วนใหญ่นึกถึงต้นทุนของ JavaScript ก็จะนึกถึงต้นทุนการดาวน์โหลดและการดำเนินการ ยิ่งการเชื่อมต่อของผู้ใช้ช้าลง การส่ง JavaScript ผ่านเครือข่ายก็จะใช้เวลานานขึ้น

เมื่อเบราว์เซอร์ขอทรัพยากร ระบบจะต้องดึงข้อมูลทรัพยากรนั้นมาและทำการขยายไฟล์ ในกรณีของทรัพยากรอย่าง JavaScript จะต้องแยกวิเคราะห์และคอมไพล์ก่อนดำเนินการ

ซึ่งอาจเป็นปัญหาได้ เนื่องจากประเภทการเชื่อมต่อเครือข่ายที่มีประสิทธิภาพที่ผู้ใช้มีอาจไม่ใช่ 3G, 4G หรือ Wi-Fi จริง คุณอาจใช้ Wi-Fi ของร้านกาแฟแต่เชื่อมต่อกับฮอตสปอตมือถือที่มีความเร็ว 2G

คุณลดต้นทุนการโอนเครือข่ายของ JavaScript ได้ดังนี้

  • ส่งเฉพาะรหัสที่ผู้ใช้ต้องการ
    • ใช้การแยกโค้ดเพื่อแบ่ง JavaScript ออกเป็นโค้ดที่สําคัญและไม่สําคัญ เครื่องมือรวมโมดูลอย่าง webpack รองรับการแยกโค้ด
    • การโหลดโค้ดที่ไม่สําคัญแบบ Lazy Loading
  • การลดขนาด
  • การบีบอัด
    • ใช้ gzip เพื่อบีบอัดทรัพยากรแบบข้อความเป็นอย่างน้อย
    • ลองใช้ Brotli ~q11 Brotli มีประสิทธิภาพดีกว่า gzip ในด้านอัตราส่วนการบีบอัด ซึ่งช่วยให้ CertSimple ประหยัดเนื้อที่ไบต์ JS ที่บีบอัดได้17% และ LinkedIn ประหยัดเวลาในการโหลดได้4%
  • การนำโค้ดที่ไม่ได้ใช้งานออก
  • การแคชโค้ดเพื่อลดการใช้งานเครือข่าย
    • ใช้การแคช HTTP เพื่อให้แน่ใจว่าเบราว์เซอร์จะแคชการตอบกลับได้อย่างมีประสิทธิภาพ กำหนดอายุการใช้งานที่เหมาะสมสำหรับสคริปต์ (max-age) และระบุโทเค็นการตรวจสอบ (ETag) เพื่อหลีกเลี่ยงการโอนไบต์ที่ไม่มีการเปลี่ยนแปลง
    • การแคช Service Worker ช่วยให้เครือข่ายแอปมีความยืดหยุ่นและให้คุณเข้าถึงฟีเจอร์ต่างๆ ได้อย่างรวดเร็ว เช่น แคชโค้ดของ V8
    • ใช้การแคชระยะยาวเพื่อหลีกเลี่ยงการต้องดึงข้อมูลทรัพยากรที่ไม่ได้เปลี่ยนแปลงใหม่ หากใช้ Webpack โปรดดูการแฮชชื่อไฟล์

แยกวิเคราะห์/คอมไพล์

เมื่อดาวน์โหลดแล้ว ต้นทุนที่หนักที่สุดอย่างหนึ่งของ JavaScript คือเวลาที่เครื่องมือ JS ใช้ในการแยกวิเคราะห์/คอมไพล์โค้ดนี้ ใน Chrome DevTools การแยกวิเคราะห์และการคอมไพล์เป็นส่วนหนึ่งของเวลา "การเขียนสคริปต์" สีเหลืองในแผงประสิทธิภาพ

ALT_TEXT_HERE

แท็บ Bottom-Up และ Call Tree จะแสดงเวลาในการแยกวิเคราะห์/คอมไพล์ที่แน่นอน

ALT_TEXT_HERE
Chrome แผงประสิทธิภาพของ DevTools > จากล่างขึ้นบน เมื่อเปิดใช้สถิติการเรียกใช้รันไทม์ของ V8 เราจะเห็นเวลาที่ใช้ในการดำเนินการในแต่ละระยะ เช่น แยกวิเคราะห์และคอมไพล์

แต่เหตุใดเรื่องนี้จึงสำคัญ

ALT_TEXT_HERE

การแยกวิเคราะห์/คอมไพล์โค้ดเป็นเวลานานอาจทำให้ผู้ใช้โต้ตอบกับเว็บไซต์ได้ช้าลงอย่างมาก ยิ่งคุณส่ง JavaScript มากเท่าใด ก็ยิ่งใช้เวลาในการแยกวิเคราะห์และคอมไพล์นานขึ้นเท่านั้นก่อนที่เว็บไซต์จะโต้ตอบได้

เมื่อพิจารณาแบบไบต์ต่อไบต์ เบราว์เซอร์จะประมวลผล JavaScript ได้ช้ากว่ารูปภาพหรือแบบอักษรเว็บที่มีขนาดเท่ากัน - Tom Dale

เมื่อเทียบกับ JavaScript นั้น รูปภาพขนาดเท่ากันมีต้นทุนการประมวลผลจำนวนมาก (ต้องถอดรหัสก่อน) แต่สำหรับฮาร์ดแวร์ในอุปกรณ์เคลื่อนที่ทั่วไป JS มีแนวโน้มที่จะส่งผลเสียต่อความสามารถในการโต้ตอบของหน้าเว็บมากกว่า

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

เมื่อพูดถึงการแยกวิเคราะห์และการคอมไพล์ที่ช้า บริบทก็มีความสำคัญ เนื่องจากเรากำลังพูดถึงโทรศัพท์มือถือทั่วไป ผู้ใช้ทั่วไปอาจมีโทรศัพท์ที่มี CPU และ GPU ที่ช้า ไม่มีแคช L2/L3 และอาจจํากัดหน่วยความจํา

ความสามารถของเครือข่ายและความสามารถของอุปกรณ์อาจไม่ตรงกันเสมอไป ผู้ใช้ที่มีการเชื่อมต่อไฟเบอร์ที่ยอดเยี่ยมไม่จำเป็นต้องมี CPU ที่ดีที่สุดในการแยกวิเคราะห์และประเมิน JavaScript ที่ส่งไปยังอุปกรณ์ ในทางกลับกัน การเชื่อมต่อเครือข่ายที่ช้ามากแต่มี CPU ที่เร็วสุดๆ ก็อาจทำให้ประสิทธิภาพลดลงเช่นกัน — Kristofer Baxter จาก LinkedIn

ด้านล่างนี้เราจะเห็นต้นทุนในการแยกวิเคราะห์ JavaScript (แบบง่าย) ที่ไม่มีการบีบอัดประมาณ 1 MB ในฮาร์ดแวร์ระดับต่ำและระดับสูง เวลาในการแยกวิเคราะห์/คอมไพล์โค้ดของโทรศัพท์ที่เร็วที่สุดในท้องตลาดกับโทรศัพท์ทั่วไปแตกต่างกัน 2-5 เท่า

ALT_TEXT_HERE
กราฟนี้เน้นไปที่เวลาในการแยกวิเคราะห์สำหรับกลุ่ม JavaScript ขนาด 1 MB (~250 KB เมื่อใช้การบีบอัด GZIP) ในเดสก์ท็อปและอุปกรณ์เคลื่อนที่ระดับต่างๆ เมื่อพิจารณาถึงต้นทุนของการแยกวิเคราะห์ ให้พิจารณาตัวเลขที่ไม่มีการบีบอัด เช่น JS ที่บีบอัดด้วย Gzip ขนาดประมาณ 250 KB ได้รับการขยายขนาดเป็นโค้ดขนาดประมาณ 1 MB

แล้วเว็บไซต์ในชีวิตจริงอย่าง CNN.com ล่ะ

ใน iPhone 8 รุ่นไฮเอนด์ ใช้เวลาเพียงประมาณ 4 วินาทีในการแยกวิเคราะห์/คอมไพล์ JS ของ CNN เมื่อเทียบกับโทรศัพท์ทั่วไป (Moto G4) ที่ใช้เวลาประมาณ 13 วินาที ซึ่งอาจส่งผลอย่างมากต่อความเร็วที่ผู้ใช้โต้ตอบกับเว็บไซต์นี้ได้อย่างเต็มที่

ALT_TEXT_HERE
ด้านบนนี้คือเวลาในการแยกวิเคราะห์ที่เปรียบเทียบประสิทธิภาพของชิป A11 Bionic ของ Apple กับ Snapdragon 617 ในฮาร์ดแวร์ Android ระดับกลาง

ข้อมูลนี้แสดงให้เห็นถึงความสำคัญของการทดสอบบนฮาร์ดแวร์ทั่วไป (เช่น Moto G4) แทนที่จะทดสอบเฉพาะโทรศัพท์ที่คุณอาจพกติดตัวอยู่ บริบทมีความสำคัญ แต่อย่างไรก็ตาม โปรดเพิ่มประสิทธิภาพสำหรับอุปกรณ์และสภาพเครือข่ายของผู้ใช้

ALT_TEXT_HERE
Google Analytics สามารถให้ข้อมูลเชิงลึกเกี่ยวกับคลาสอุปกรณ์เคลื่อนที่ที่ผู้ใช้จริงใช้เข้าถึงเว็บไซต์ วิธีนี้จะช่วยให้เข้าใจข้อจำกัดของ CPU/GPU จริงที่อุปกรณ์ทำงานอยู่

เราส่ง JavaScript มากเกินไปจริงหรือ อาจจะเป็นไปได้นะ :)

เมื่อใช้ HTTP Archive (เว็บไซต์ยอดนิยมประมาณ 500, 000 เว็บไซต์) เพื่อวิเคราะห์สถานะของ JavaScript บนอุปกรณ์เคลื่อนที่ เราพบว่าเว็บไซต์ 50% ใช้เวลานานกว่า 14 วินาทีในการโต้ตอบ เว็บไซต์เหล่านี้ใช้เวลาถึง 4 วินาทีในการแยกวิเคราะห์และคอมไพล์ JS

ALT_TEXT_HERE

อย่าลืมคำนึงถึงเวลาในการดึงข้อมูลและประมวลผล JS และทรัพยากรอื่นๆ ด้วย จึงไม่น่าแปลกใจที่ผู้ใช้อาจต้องรอสักพักก่อนที่หน้าเว็บจะพร้อมใช้งาน เราปรับปรุงให้ดีกว่านี้ได้อย่างแน่นอน

การนำ JavaScript ที่ไม่สําคัญออกจากหน้าเว็บสามารถลดเวลาในการรับส่ง การแยกวิเคราะห์และการคอมไพล์ที่ต้องใช้ CPU มาก และลดการใช้หน่วยความจําที่อาจเกิดขึ้น วิธีนี้ยังช่วยให้หน้าเว็บโต้ตอบได้เร็วขึ้นด้วย

เวลาดำเนินการ

ไม่เพียงการแยกวิเคราะห์และการคอมไพล์เท่านั้นที่มีค่าใช้จ่าย การเรียกใช้ JavaScript (การเรียกใช้โค้ดเมื่อแยกวิเคราะห์/คอมไพล์แล้ว) เป็นหนึ่งในการดำเนินการที่ต้องเกิดขึ้นในเทรดหลัก เวลาที่ใช้ในการดำเนินการนานยังอาจทำให้ผู้ใช้โต้ตอบกับเว็บไซต์ได้ช้าลงด้วย

ALT_TEXT_HERE

หากสคริปต์ทำงานนานกว่า 50 มิลลิวินาที เวลาในการตอบสนองจะล่าช้าตามเวลาที่ใช้ในการดาวน์โหลด คอมไพล์ และเรียกใช้ JS ทั้งหมด Alex Russell

ด้วยเหตุนี้ JavaScript จึงควรอยู่ในรูปแบบข้อมูลโค้ดขนาดเล็กเพื่อหลีกเลี่ยงการล็อกเทรดหลัก ตรวจสอบว่าคุณลดปริมาณงานที่ดำเนินการในระหว่างการดําเนินการได้หรือไม่

ค่าใช้จ่ายอื่นๆ

JavaScript อาจส่งผลต่อประสิทธิภาพของหน้าเว็บในลักษณะอื่นๆ ดังนี้

  • ความทรงจำ หน้าเว็บอาจดูเหมือนกระตุกหรือหยุดชั่วคราวบ่อยครั้งเนื่องจาก GC (การเก็บขยะ) เมื่อเบราว์เซอร์เรียกคืนหน่วยความจำ การดำเนินการ JS จะหยุดชั่วคราว ดังนั้นเบราว์เซอร์ที่รวบรวมขยะบ่อยๆ จึงหยุดการดำเนินการบ่อยกว่าที่เราต้องการ หลีกเลี่ยงการรั่วไหลของหน่วยความจำและการหยุด gc บ่อยๆ เพื่อไม่ให้หน้าเว็บกระตุก
  • ในระหว่างรันไทม์ JavaScript ที่ทำงานเป็นเวลานานอาจบล็อกเทรดหลัก ซึ่งส่งผลให้หน้าเว็บไม่ตอบสนอง การแบ่งงานออกเป็นชิ้นเล็กๆ (โดยใช้ requestAnimationFrame() หรือ requestIdleCallback() สำหรับการกําหนดเวลา) ช่วยลดปัญหาการตอบสนอง ซึ่งจะช่วยปรับปรุง Interaction to Next Paint (INP) ได้

รูปแบบการลดต้นทุนการแสดงผล JavaScript

เมื่อพยายามทำให้เวลาในการแยกวิเคราะห์/คอมไพล์และเวลาในการส่งผ่านเครือข่ายสําหรับ JavaScript ช้าลง ก็มีรูปแบบที่จะช่วยได้ เช่น การแบ่งกลุ่มตามเส้นทางหรือ PRPL

PRPL

PRPL (Push, Render, Pre-cache, Lazy-load) คือรูปแบบที่เพิ่มประสิทธิภาพเพื่อการโต้ตอบผ่านการแยกโค้ดและการแคชอย่างมีประสิทธิภาพ

ALT_TEXT_HERE

มาดูภาพผลลัพธ์ที่อาจเกิดขึ้นกัน

เราวิเคราะห์เวลาในการโหลดของเว็บไซต์บนอุปกรณ์เคลื่อนที่และ Progressive Web App ยอดนิยมโดยใช้สถิติการเรียกใช้รันไทม์ของ V8 เราเห็นว่าเวลาในการแยกวิเคราะห์ (แสดงเป็นสีส้ม) เป็นส่วนสําคัญที่เว็บไซต์เหล่านี้ใช้เวลา

ALT_TEXT_HERE

Wego เป็นเว็บไซต์ที่ใช้ PRPL ซึ่งรักษาเวลาในการแยกวิเคราะห์เส้นทางให้ต่ำได้ ทำให้โต้ตอบได้อย่างรวดเร็ว เว็บไซต์อื่นๆ อีกหลายแห่งข้างต้นใช้การแยกโค้ดและงบประมาณด้านประสิทธิภาพเพื่อพยายามลดต้นทุน JS

การเริ่มต้นแบบโปรเกรสซีฟ

เว็บไซต์จํานวนมากเพิ่มประสิทธิภาพการมองเห็นเนื้อหาโดยเสียค่าใช้จ่ายด้านความสามารถในการโต้ตอบ หากต้องการการแสดงผลครั้งแรกที่รวดเร็วเมื่อคุณมีกลุ่ม JavaScript ขนาดใหญ่ นักพัฒนาซอฟต์แวร์อาจใช้การแสดงผลฝั่งเซิร์ฟเวอร์ในบางครั้ง จากนั้น "อัปเกรด" เพื่อแนบตัวแฮนเดิลเหตุการณ์เมื่อมีการดึงข้อมูล JavaScript ในที่สุด

โปรดระมัดระวัง เนื่องจากการดำเนินการนี้อาจมีค่าใช้จ่าย 1) โดยทั่วไปแล้วคุณส่งการตอบกลับ HTML ที่ใหญ่ขึ้น ซึ่งอาจทำให้การโต้ตอบของเราลดลง 2) อาจทำให้ผู้ใช้รู้สึกอึดอัดเมื่อครึ่งหนึ่งของประสบการณ์ไม่สามารถโต้ตอบได้จนกว่า JavaScript จะประมวลผลเสร็จ

การเริ่มต้นแบบเป็นขั้นเป็นตอนอาจเป็นแนวทางที่ดีกว่า ส่งหน้าเว็บที่ใช้งานได้น้อยที่สุด (ประกอบด้วย HTML/JS/CSS ที่จําเป็นสําหรับเส้นทางปัจจุบันเท่านั้น) เมื่อทรัพยากรเข้ามามากขึ้น แอปจะโหลดแบบเลื่อนเวลาและปลดล็อกฟีเจอร์เพิ่มเติมได้

ALT_TEXT_HERE
Progressive Bootstrapping โดย Paul Lewis

การโหลดโค้ดตามสัดส่วนกับสิ่งที่แสดงอยู่คือเป้าหมายสูงสุด PRPL และ Progressive Bootstrapping เป็นรูปแบบที่ช่วยให้บรรลุเป้าหมายนี้ได้

สรุป

ขนาดการส่งเป็นสิ่งสำคัญสำหรับเครือข่ายระดับล่าง เวลาแยกวิเคราะห์มีความสำคัญสำหรับอุปกรณ์ที่กําหนดโดย CPU การรักษาค่าเหล่านี้ให้ต่ำเป็นเรื่องสำคัญ

ทีมต่างๆ ประสบความสําเร็จเมื่อใช้งบประมาณด้านประสิทธิภาพที่เข้มงวดเพื่อรักษาเวลาในการส่งและแยกวิเคราะห์/คอมไพล์ JavaScript ให้ต่ำ ดู "Can You Afford It?: งบประมาณด้านประสิทธิภาพของเว็บในชีวิตจริง"เพื่อดูคําแนะนําเกี่ยวกับงบประมาณสําหรับอุปกรณ์เคลื่อนที่

ALT_TEXT_HERE
การคำนึงถึง "Headroom" ของ JS ว่าการตัดสินใจด้านสถาปัตยกรรมที่เราทำไว้จะเหลือพื้นที่มากน้อยเพียงใดสำหรับตรรกะของแอป

หากคุณกำลังสร้างเว็บไซต์ที่กําหนดเป้าหมายเป็นอุปกรณ์เคลื่อนที่ ให้พยายามพัฒนาบนฮาร์ดแวร์ที่เป็นแบบอย่าง รักษาเวลาแยกวิเคราะห์/คอมไพล์ JavaScript ให้ต่ำ และนํางบประมาณด้านประสิทธิภาพมาใช้เพื่อให้ทีมของคุณควบคุมต้นทุน JavaScript ได้

ดูข้อมูลเพิ่มเติม