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

ซึ่งอาจเป็นปัญหาได้ เนื่องจากประเภทการเชื่อมต่อเครือข่ายที่มีประสิทธิภาพที่ผู้ใช้มีอาจไม่ใช่ 3G, 4G หรือ Wi-Fi จริงๆ คุณอาจใช้ Wi-Fi ของร้านกาแฟแต่เชื่อมต่อกับฮอตสปอตเครือข่ายมือถือด้วยความเร็ว 2G
คุณลดค่าใช้จ่ายในการโอนเครือข่ายของ JavaScript ได้โดยทำดังนี้
- ส่งเฉพาะโค้ดที่ผู้ใช้ต้องการ
- ใช้การแยกโค้ดเพื่อแบ่ง JavaScript ออกเป็นส่วนที่สำคัญและไม่สำคัญ เครื่องมือรวมโมดูล เช่น webpack รองรับการแยกโค้ด
- การโหลดแบบ Lazy Loading ในโค้ดที่ไม่สำคัญ
- การลดขนาด
- ใช้ UglifyJS เพื่อลดขนาดโค้ด ES5
- ใช้ babel-minify หรือ uglify-es เพื่อลดขนาด ES2015+
- การบีบอัด
- การนำโค้ดที่ไม่ได้ใช้ออก
- ระบุโอกาสสำหรับโค้ดที่สามารถนำออกหรือโหลดแบบ Lazy Loading ได้ด้วยการครอบคลุมของโค้ดในเครื่องมือสำหรับนักพัฒนาเว็บ
- ใช้ babel-preset-env และ browserlist เพื่อหลีกเลี่ยงการทำการ Transpile ฟีเจอร์ที่มีอยู่แล้วในเบราว์เซอร์ที่ทันสมัย นักพัฒนาขั้นสูงอาจพบว่าการวิเคราะห์แพ็กเกจ webpack อย่างรอบคอบช่วยระบุโอกาสในการตัดทรัพยากร Dependency ที่ไม่จำเป็นออกได้
- สำหรับการตัดโค้ด โปรดดู tree-shaking, การเพิ่มประสิทธิภาพขั้นสูงของ Closure Compiler และปลั๊กอินการตัดแต่งไลบรารี เช่น lodash-babel-plugin หรือ ContextReplacementPlugin ของ webpack สำหรับไลบรารีอย่าง Moment.js
- การแคชโค้ดเพื่อลดการเดินทางของเครือข่าย
- ใช้การแคช HTTP เพื่อให้เบราว์เซอร์แคชการตอบกลับได้อย่างมีประสิทธิภาพ กำหนดอายุการใช้งานที่เหมาะสมสำหรับสคริปต์ (max-age) และระบุโทเค็นสำหรับตรวจสอบความถูกต้อง (ETag) เพื่อหลีกเลี่ยงการโอนไบต์ที่ไม่มีการเปลี่ยนแปลง
- การแคช Service Worker ช่วยให้เครือข่ายแอปของคุณมีความยืดหยุ่นและช่วยให้คุณเข้าถึงฟีเจอร์ต่างๆ เช่น แคชโค้ดของ V8 ได้อย่างรวดเร็ว
- ใช้การแคชระยะยาวเพื่อหลีกเลี่ยงการดึงข้อมูลทรัพยากรที่ไม่มีการเปลี่ยนแปลงซ้ำ หากใช้ Webpack โปรดดูการแฮชชื่อไฟล์
แยกวิเคราะห์/คอมไพล์
เมื่อดาวน์โหลดแล้ว ต้นทุนที่สูงที่สุดอย่างหนึ่งของ JavaScript คือเวลาที่เครื่องมือ JS ใช้ในการแยกวิเคราะห์/คอมไพล์โค้ดนี้ ในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome การแยกวิเคราะห์และการคอมไพล์เป็นส่วนหนึ่งของเวลา "การเขียนสคริปต์" สีเหลืองในแผงประสิทธิภาพ

แท็บจากล่างขึ้นบนและแผนผังการเรียกจะแสดงเวลาแยกวิเคราะห์/คอมไพล์ที่แน่นอน ดังนี้
แต่ทำไมเรื่องนี้จึงสำคัญ

การใช้เวลานานในการแยกวิเคราะห์/คอมไพล์โค้ดอาจทำให้ผู้ใช้โต้ตอบกับเว็บไซต์ได้ช้าลงอย่างมาก ยิ่งคุณส่ง JavaScript มากเท่าใด ก็จะยิ่งใช้เวลาในการแยกวิเคราะห์และคอมไพล์นานขึ้นก่อนที่เว็บไซต์จะโต้ตอบได้
เมื่อเทียบกันแบบไบต์ต่อไบต์ JavaScript มีค่าใช้จ่ายในการประมวลผลสำหรับเบราว์เซอร์มากกว่ารูปภาพหรือเว็บฟอนต์ที่มีขนาดเท่ากัน - Tom Dale
เมื่อเทียบกับ JavaScript แล้ว การประมวลผลรูปภาพที่มีขนาดเท่ากันมีต้นทุนจำนวนมาก (ยังคงต้องถอดรหัส) แต่ในฮาร์ดแวร์อุปกรณ์เคลื่อนที่โดยเฉลี่ย JS มีแนวโน้มที่จะส่งผลเสียต่อการโต้ตอบของหน้าเว็บมากกว่า
เมื่อเราพูดถึงการแยกวิเคราะห์และการคอมไพล์ที่ช้า บริบทเป็นสิ่งสำคัญ เรากำลังพูดถึงโทรศัพท์มือถือโดยเฉลี่ย ผู้ใช้ทั่วไปอาจมีโทรศัพท์ที่มี CPU และ GPU ช้า ไม่มีแคช L2/L3 และอาจมีหน่วยความจำจำกัด
ความสามารถของเครือข่ายและความสามารถของอุปกรณ์อาจไม่ตรงกันเสมอไป ผู้ใช้ที่มีการเชื่อมต่อไฟเบอร์ที่ยอดเยี่ยมอาจไม่มี CPU ที่ดีที่สุดในการแยกวิเคราะห์และประเมิน JavaScript ที่ส่งไปยังอุปกรณ์ของตน ในทางกลับกันก็เช่นกัน… การเชื่อมต่อเครือข่ายแย่มาก แต่ CPU เร็วมาก — Kristofer Baxter, LinkedIn
ด้านล่างนี้เราจะเห็นต้นทุนในการแยกวิเคราะห์ JavaScript (แบบง่าย) ที่คลายการบีบอัดแล้วขนาดประมาณ 1 MB ในฮาร์ดแวร์ระดับต่ำและระดับสูง โทรศัพท์ที่เร็วที่สุดในตลาดและโทรศัพท์ทั่วไปมีเวลาในการแยกวิเคราะห์/คอมไพล์โค้ดต่างกัน 2-5 เท่า
แล้วเว็บไซต์ในชีวิตจริงอย่าง CNN.com ล่ะ
iPhone 8 ระดับไฮเอนด์ใช้เวลาเพียงประมาณ 4 วินาทีในการแยกวิเคราะห์/คอมไพล์ JS ของ CNN เทียบกับประมาณ 13 วินาทีสำหรับโทรศัพท์ทั่วไป (Moto G4) ซึ่งอาจส่งผลอย่างมากต่อความรวดเร็วที่ผู้ใช้จะโต้ตอบกับเว็บไซต์นี้ได้อย่างเต็มที่
ซึ่งแสดงให้เห็นถึงความสำคัญของการทดสอบในฮาร์ดแวร์ระดับปานกลาง (เช่น Moto G4) แทนที่จะทดสอบเฉพาะในโทรศัพท์ที่คุณอาจมีอยู่แล้ว อย่างไรก็ตาม บริบทก็เป็นสิ่งสำคัญ: เพิ่มประสิทธิภาพให้เหมาะกับอุปกรณ์และสภาพเครือข่ายที่ผู้ใช้มี
เราส่ง JavaScript มากเกินไปจริงๆ หรือ เอ่อ อาจจะนะ :)
เมื่อใช้ HTTP Archive (เว็บไซต์ยอดนิยมประมาณ 5 แสนแห่ง) เพื่อวิเคราะห์สถานะของ JavaScript บนอุปกรณ์เคลื่อนที่ เราพบว่าเว็บไซต์ 50% ใช้เวลามากกว่า 14 วินาทีในการโต้ตอบ เว็บไซต์เหล่านี้ใช้เวลาถึง 4 วินาทีในการแยกวิเคราะห์และคอมไพล์ JS

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

หากสคริปต์ใช้เวลาดำเนินการนานกว่า 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) เป็นรูปแบบที่เพิ่มประสิทธิภาพสำหรับการโต้ตอบผ่านการแยกโค้ดและการแคชอย่างเข้มงวด ดังนี้

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

Wego ซึ่งเป็นเว็บไซต์ที่ใช้ PRPL สามารถรักษาเวลาในการแยกวิเคราะห์เส้นทางให้ต่ำได้ ทำให้โต้ตอบได้อย่างรวดเร็ว เว็บไซต์อื่นๆ จำนวนมากที่กล่าวถึงข้างต้นได้นำการแยกโค้ดและงบประมาณด้านประสิทธิภาพมาใช้เพื่อพยายามลดต้นทุน JS
การบูตสแตรปแบบต่อเนื่อง
เว็บไซต์จำนวนมากเพิ่มประสิทธิภาพการมองเห็นเนื้อหาโดยแลกกับการสูญเสียความสามารถในการโต้ตอบ เพื่อให้ได้การแสดงผลครั้งแรกที่รวดเร็วเมื่อคุณมีแพ็กเกจ JavaScript ขนาดใหญ่ บางครั้งนักพัฒนาซอฟต์แวร์จะใช้การแสดงผลฝั่งเซิร์ฟเวอร์ จากนั้น "อัปเกรด" เพื่อแนบเครื่องจัดการเหตุการณ์เมื่อดึงข้อมูล JavaScript ในที่สุด
โปรดระมัดระวัง เนื่องจากวิธีนี้มีค่าใช้จ่าย คุณ 1) มักจะส่งการตอบกลับ HTML ที่ใหญ่ขึ้น ซึ่งอาจทำให้การโต้ตอบของเราล่าช้า 2) อาจทำให้ผู้ใช้รู้สึกแปลกๆ เนื่องจากประสบการณ์ครึ่งหนึ่งไม่สามารถโต้ตอบได้จริงจนกว่า JavaScript จะประมวลผลเสร็จ
การใช้ Progressive Bootstrapping อาจเป็นแนวทางที่ดีกว่า ส่งหน้าเว็บที่มีฟังก์ชันการทำงานขั้นต่ำ (ประกอบด้วย HTML/JS/CSS ที่จำเป็นสำหรับเส้นทางปัจจุบันเท่านั้น) เมื่อมีทรัพยากรมากขึ้น แอปจะโหลดแบบ Lazy Loading และปลดล็อกฟีเจอร์เพิ่มเติมได้
การโหลดโค้ดตามสัดส่วนของสิ่งที่อยู่ในมุมมองคือเป้าหมายสูงสุด PRPL และ Progressive Bootstrapping เป็นรูปแบบที่ช่วยให้บรรลุเป้าหมายนี้ได้
บทสรุป
ขนาดการส่งข้อมูลมีความสำคัญอย่างยิ่งสำหรับเครือข่ายระดับล่าง เวลาในการแยกวิเคราะห์เป็นสิ่งสำคัญ สำหรับอุปกรณ์ที่เชื่อมโยงกับ CPU การรักษาอัตราเหล่านี้ให้ต่ำจึงเป็นสิ่งสำคัญ
ทีมต่างๆ ประสบความสำเร็จในการนำงบประมาณด้านประสิทธิภาพที่เข้มงวดมาใช้เพื่อรักษาเวลาในการส่งและการแยกวิเคราะห์/คอมไพล์ JavaScript ให้อยู่ในระดับต่ำ ดูบทความ "Can You Afford It?: Real-world Web Performance Budgets" เพื่อดูคำแนะนำเกี่ยวกับงบประมาณสำหรับอุปกรณ์เคลื่อนที่
หากคุณกำลังสร้างเว็บไซต์ที่กำหนดเป้าหมายเป็นอุปกรณ์เคลื่อนที่ ให้พยายามอย่างเต็มที่เพื่อพัฒนาบนฮาร์ดแวร์ตัวแทน รักษาเวลาในการแยกวิเคราะห์/คอมไพล์ JavaScript ให้ต่ำ และใช้งบประมาณด้านประสิทธิภาพเพื่อให้มั่นใจว่าทีมของคุณจะสามารถติดตามต้นทุน JavaScript ได้
ดูข้อมูลเพิ่มเติม
- Chrome Dev Summit 2017 - แนวทางปฏิบัติแนะนำสำหรับการโหลดสมัยใหม่
- ประสิทธิภาพการเริ่มต้นทำงานของ JavaScript
- การแก้ปัญหาวิกฤตประสิทธิภาพของเว็บ — Nolan Lawson
- คุณมีงบประมาณเพียงพอหรือไม่ งบประมาณด้านประสิทธิภาพในสถานการณ์จริง — Alex Russell
- การประเมินเฟรมเวิร์กและไลบรารีของเว็บ — Kristofer Baxter
- ผลลัพธ์การทดสอบของ Cloudflare กับ Brotli สำหรับการบีบอัด (โปรดทราบว่า Brotli แบบไดนามิกที่มีคุณภาพสูงกว่าอาจทำให้การแสดงผลหน้าเว็บครั้งแรกล่าช้า ดังนั้นโปรดประเมินอย่างรอบคอบ คุณอาจต้องการบีบอัดแบบคงที่แทน)
- Performance Futures — Sam Saccone