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

Addy Osmani
Addy Osmani

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

เครือข่าย

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

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

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

คุณลดค่าใช้จ่ายในการโอนเครือข่ายของ JavaScript ได้ผ่านช่องทางต่อไปนี้

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

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

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

ALT_TEXT_HERE

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

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

แต่ทำไมสิ่งนี้จึงสำคัญ

ALT_TEXT_HERE

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

ไบต์ต่อไบต์ JavaScript ที่เบราว์เซอร์ประมวลผลมีต้นทุนสูงกว่ารูปภาพหรือเว็บฟอนต์ที่มีขนาดเท่ากัน — Tom Dale

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

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

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

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

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

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

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

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

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

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

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

เราส่ง JavaScript มากเกินไปจริงๆ ใช่ไหม เอ่อ อาจจะ :)

การใช้ที่เก็บถาวรของ HTTP (เว็บไซต์ประมาณ 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 จะหยุดชั่วคราวเพื่อให้เบราว์เซอร์ที่รวบรวมไฟล์ขยะสามารถหยุดการดำเนินการชั่วคราวได้บ่อยกว่าที่เราอาจต้องการ โปรดหลีกเลี่ยงการรั่วไหลของหน่วยความจำและการหยุดชั่วคราวบ่อยๆ สำหรับ GCP เพื่อให้หน้าไม่ราบรื่น
  • ในระหว่างรันไทม์ JavaScript ที่ใช้เวลานานอาจบล็อกเทรดหลักซึ่งทำให้หน้าไม่ตอบสนอง การแบ่งงานออกเป็นส่วนเล็กๆ (โดยใช้ requestAnimationFrame() หรือ requestIdleCallback() ในการกำหนดเวลา) จะช่วยลดปัญหาการตอบสนองได้ ซึ่งจะช่วยปรับปรุงการโต้ตอบกับ Next Paint (INP)

รูปแบบสำหรับการลดต้นทุนการนำส่ง JavaScript

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

PRPL

PRPL (พุช, แสดงผล, แคชล่วงหน้า, การโหลดแบบ Lazy Loading) เป็นรูปแบบที่เพิ่มประสิทธิภาพสำหรับการโต้ตอบผ่านการแยกโค้ดและการแคชเชิงรุก

ALT_TEXT_HERE

มาลองดูภาพผลลัพธ์ที่จะได้รับกันเลย

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

ALT_TEXT_HERE

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

การเปิดเครื่องแบบโปรเกรสซีฟ

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

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

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

ALT_TEXT_HERE
การเปิดเครื่องแบบ Progressive โดย Paul Lewis

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

บทสรุป

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

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

ALT_TEXT_HERE
การพิจารณาว่า JS "ช่องว่าง" ของการตัดสินใจด้านสถาปัตยกรรมที่เราทำนั้นมีประโยชน์มากเพียงใดที่เราจะทำให้เราต้องใช้ตรรกะของแอป

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

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