ตอบสนองการปรับปรุงประสิทธิภาพ
เฮ้! ฉันชื่อ Çağlayan Yanıkoğlu ฉันทำงานเป็น Frontend Developer ที่Jotform ฉันยังเป็นผู้สอน/ที่ปรึกษาส่วนหน้าของPatika.devและkodluyoruz
ฉันจะเผยแพร่บทความทุกวันอาทิตย์เพื่อให้คุณได้รับความรู้ด้านเทคนิค โดยส่วนใหญ่เกี่ยวกับการพัฒนา FrontEnd พร้อมแฮชแท็ก#SundayTechMusings
ฉันจะบอกคุณ ว่าฉันได้เรียนรู้อะไรบ้างจากประสบการณ์การทำงานและการวิจัยจากบล็อกเกี่ยวกับReact Performance Optimization
หัวข้อของวันนี้คือ React Performance Optimization ซึ่งฉันใช้ในชีวิตการทำงานและยังรวมถึงบางจุดที่ฉันได้เรียนรู้จากโครงการเสริมของฉัน ถึงบล็อกจะยาวแต่ฉันหวังว่าคุณจะอ่านจนจบ :)
ประสิทธิภาพของเว็บหมายถึง:
- เนื้อหาไซต์โหลดและแสดงผลในเว็บเบราว์เซอร์ได้เร็วเพียงใด
- ตอบสนองต่อการโต้ตอบของผู้ใช้ได้ดีเพียงใด
- บรรลุเป้าหมายที่ดีสำหรับประสิทธิภาพของเว็บเมื่อผู้ใช้ไม่ทราบถึงประสิทธิภาพ
- รักษาประสบการณ์ของผู้ใช้ในเชิงบวก
- ปรับปรุงอัตราคอนเวอร์ชั่น: จากการวิจัยของ Akamai ความล่าช้าในการโหลดครั้งที่ 2 อาจทำให้คอนเวอร์ชั่นลดลง 7 เปอร์เซ็นต์
ความเร็วของไซต์ส่งผลโดยตรงต่ออัตราตีกลับ การแปลง รายได้ ความพึงพอใจของผู้ใช้ และการจัดอันดับของเครื่องมือค้นหา
การปรับปรุงประสิทธิภาพการตอบสนอง
ในแอปพลิเคชัน React รับประกัน UI ที่รวดเร็วมากตามค่าเริ่มต้น อย่างไรก็ตาม เมื่อแอปพลิเคชันเติบโตขึ้น นักพัฒนาซอฟต์แวร์อาจประสบปัญหาด้านประสิทธิภาพ
ก่อนที่จะพยายามเพิ่มประสิทธิภาพ เราต้องเข้าใจว่า React ทำงานอย่างไร
เรามีคีย์สำคัญสองคีย์ใน React; Virtual Dom (Document Object Model)และDiffing
Virtual Dom เป็นสำเนาของ DOM จริง
เมื่อเราสร้างองค์ประกอบที่แสดงผล React จะสร้างDOM เสมือนสำหรับโครงสร้างองค์ประกอบในองค์ประกอบ ตอนนี้ เมื่อใดก็ตามที่สถานะของส่วนประกอบเปลี่ยนไป React จะสร้างทรี DOM เสมือนขึ้นใหม่และเปรียบเทียบผลลัพธ์กับการเรนเดอร์ก่อนหน้า
จากนั้นจะอัปเดตองค์ประกอบที่เปลี่ยนแปลงใน DOM จริงเท่านั้น กระบวนการนี้เรียกว่าความแตกต่าง
React ใช้แนวคิดของ DOM เสมือนเพื่อลดค่าใช้จ่ายในการแสดงผลหน้าเว็บซ้ำเนื่องจาก DOM จริงนั้นมีราคาแพงในการจัดการ
สิ่งนี้ดีมากเพราะมันเร่งเวลาการเรนเดอร์ UI อย่างไรก็ตาม แนวคิดนี้อาจทำให้แอปที่ซับซ้อนทำงานช้าลงได้หากไม่ได้รับการจัดการที่ดี
สิ่งที่เราสามารถอนุมานได้จากที่นี่คือการเปลี่ยนแปลงสถานะในส่วนประกอบ React ทำให้เกิดการเรนเดอร์ซ้ำ ในทำนองเดียวกัน เมื่อ state ส่งผ่านไปยังส่วนประกอบลูกเป็น prop มันจะเรนเดอร์ลูกใหม่ และอื่นๆ ซึ่งเป็นเรื่องปกติเพราะ React ต้องอัปเดต UI
1. ให้รัฐท้องถิ่น แต่ทำไม
- ในการตอบสนอง ตราบใดที่องค์ประกอบหลักแสดงผลซ้ำ ส่วนประกอบย่อยทั้งหมดจะแสดงผลใหม่
- ในกรณีส่วนใหญ่ การแสดงผลซ้ำนี้ไม่ควรทำให้เกิดปัญหาด้านประสิทธิภาพ
- อย่างไรก็ตาม หากส่วนประกอบที่ไม่ได้รับผลกระทบทำให้การคำนวณมีราคาแพง และเราสังเกตเห็นปัญหาด้านประสิทธิภาพ เราควรเพิ่มประสิทธิภาพแอปพลิเคชัน React ของเรา
สำหรับส่วนประกอบขนาดเล็กนี้ การเรนเดอร์ใหม่อาจไม่สำคัญ แต่ให้นึกถึงส่วนประกอบที่มีราคาแพง
แล้วเราจะแก้ไขได้อย่างไร?
เราสร้างส่วนประกอบใหม่ซึ่งเป็น FormInput และย้ายสถานะไปยังส่วนประกอบในเครื่อง ตอนนี้หากสถานะ FormInput เปลี่ยนไป จะไม่มีผลกระทบกับ ChildComponent
ดังนั้นเราจึงควรรักษารัฐในท้องถิ่นหากทำได้ ตัวอย่างเช่น; สถานะโมดอล สถานะอินพุตการค้นหา ฯลฯ
2. การท่องจำ
- แลกเปลี่ยนพื้นที่หน่วยความจำเป็นเวลา
จะบันทึกผลลัพธ์ไว้ในหน่วยความจำ
มี 3 เทคนิคสำหรับการท่องจำ;
1-) React.memo (ส่วนประกอบของฟังก์ชัน) / React.PureComponents (ส่วนประกอบของคลาส)
2-) useCallback hook
3-) useMemo hook
โดยใช้React.memo()
React.memoเป็นส่วนประกอบที่มีลำดับสูงกว่าซึ่งใช้เพื่อห่อหุ้มส่วนประกอบที่ใช้งานได้จริง เพื่อป้องกันการเรนเดอร์ซ้ำ หากอุปกรณ์ประกอบฉากที่ได้รับในส่วนประกอบนั้นไม่เคยเปลี่ยนแปลง
React.memo()ทำงานได้ค่อนข้างดีเมื่อเราส่งผ่านค่าดั้งเดิม เช่น ตัวเลขในตัวอย่างของเรา และหากคุณคุ้นเคยกับความเท่าเทียมกันของการอ้างอิงค่าดั้งเดิมจะเท่ากับค่าอ้างอิงเสมอและส่งคืนค่าจริงหากค่าไม่เปลี่ยนแปลง
ในทางกลับกัน ค่าที่ไม่ใช่ค่าดั้งเดิม เช่นobjectซึ่งรวมถึงอาร์เรย์และฟังก์ชัน จะส่งกลับค่าเท็จระหว่างการแสดงผลซ้ำเสมอ เนื่องจากค่าเหล่านี้ชี้ไปยังช่องว่างต่างๆ ในหน่วยความจำ
การใช้useCallbackตะขอ
ด้วยuseCallbackHook incrementCountฟังก์ชันจะกำหนดใหม่เมื่อcountอาเรย์ขึ้นต่อกันเปลี่ยนแปลง เท่านั้น
const incrementCount = React.useCallback(() => setCount(count + 1), [count]);
เนื่องจากฟังก์ชันเป็นประเภทอ็อบเจกต์ซึ่งเป็นประเภทผู้อ้างอิง และในการเรนเดอร์ทุกครั้ง มันจะสร้างอินสแตนซ์อื่นขึ้นมา ดังนั้นเมื่อเราใช้ usecallback มันจะแคชอินสแตนซ์ของฟังก์ชันในการเรนเดอร์ทุกครั้ง จากนั้น ChildComponent จะไม่เรนเดอร์ซ้ำ
การใช้useMemoตะขอ
เมื่อ prop ที่เราส่งผ่านไปยังส่วนประกอบลูกเป็นอาร์เรย์หรือวัตถุ เราสามารถใช้ Hook useMemoเพื่อบันทึกค่าระหว่างการเรนเดอร์ ดังที่เราได้เรียนรู้ข้างต้น ค่าเหล่านี้ชี้ไปยังช่องว่างต่างๆ ในหน่วยความจำและเป็นค่าใหม่ทั้งหมด
คุณยังสามารถใช้useMemoHook เพื่อหลีกเลี่ยงการคำนวณค่าที่แพงเท่ากันซ้ำในส่วนประกอบ ช่วยให้เราสามารถจดจำค่าเหล่านี้และคำนวณใหม่ได้เฉพาะเมื่อการอ้างอิงเปลี่ยนไป
เช่นเดียวกับuseCallbackHook useMemoยังคาดหวังฟังก์ชันและอาร์เรย์ของการพึ่งพา
useCallback กับ useMemo
ดังที่คุณเห็นในภาพด้านบนuseCallbackแคชฟังก์ชันในหน่วยความจำ แต่useMemoแคชผลลัพธ์
เราต้องจดจำส่วนประกอบเมื่อจำเป็นเท่านั้น
เนื่องจากหากเราใช้เทคนิคการจำสำหรับส่วนประกอบหรือฟังก์ชันทั้งหมด เราจะเพิ่มความซับซ้อนของโค้ดและอาจสูญเสียประสิทธิภาพ
ดังนั้น เมื่อใดที่เราควรใช้ React.memo/useCallback/useMemo?
- การประมวลผลข้อมูลจำนวนมาก
- การทำงานกับกราฟและแผนภูมิเชิงโต้ตอบ
- การใช้แอนิเมชั่น
- เมื่อฟังก์ชันมีสถานะภายในบางอย่าง เช่น เมื่อฟังก์ชันถูกดีบาวน์หรือควบคุมปริมาณ
- การใช้แฟรกเมนต์จะลดจำนวนแท็กพิเศษ
- แต่ละองค์ประกอบควรมีแท็กหลักเดียว
- ป้องกันไม่ให้องค์ประกอบพิเศษของ dom แสดงผล
return (
<>
<h1>This is header</h1>
<p>Hello Medium</p>
</>
)
แนวคิดของการรวมกลุ่มมีประโยชน์เพราะช่วยลดจำนวนคำขอ HTTP ที่เพจสามารถจัดการได้ อย่างไรก็ตาม เมื่อแอปพลิเคชันเติบโตขึ้น ขนาดไฟล์ก็จะเพิ่มขึ้น ซึ่งจะเป็นการเพิ่มไฟล์บันเดิล เมื่อถึงจุดหนึ่ง การเพิ่มไฟล์อย่างต่อเนื่องนี้จะทำให้การโหลดหน้าเว็บเริ่มต้นช้าลง ซึ่งทำให้ความพึงพอใจของผู้ใช้ลดลง
ด้วยการแยกโค้ด React ช่วยให้เราสามารถแยกไฟล์บันเดิลขนาดใหญ่ออกเป็นหลาย ๆ ชิ้นโดยใช้ไดนามิกimport()ตามด้วยการโหลดแบบขี้เกียจตามต้องการโดยใช้ไฟล์React.lazy. กลยุทธ์นี้ปรับปรุงประสิทธิภาพหน้าของแอปพลิเคชัน React ที่ซับซ้อนอย่างมาก
import React, { useState, Suspense } from "react";
const Home = React.lazy(() => import("./components/Home"));
const About = React.lazy(() => import("./components/About"));
function App() {
const [page, setPage] = useState("home");
return (
<div>
{page === "home" && (
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
)}
{page === "about" && (
<Suspense fallback={<div>Loading...</div>}>
<About />
</Suspense>
)}
<div>
<button onClick={() => setPage("home")}>Home</button>
<button onClick={() => setPage("about")}>About</button>
</div>
</div>
);
}
export default App;
- หน้าต่าง; แสดงผลไปยัง DOM เฉพาะส่วนที่มองเห็นได้สำหรับผู้ใช้
- เมื่อเลื่อน ให้แทนที่รายการที่ออกจากวิวพอร์ต
- เทคนิคนี้สามารถปรับปรุงประสิทธิภาพการแสดงผลของรายการขนาดใหญ่ได้อย่างมาก
แพ็คเกจ npm ยอดนิยม: react-window, react-virtualized
6. ขี้เกียจโหลดภาพ
- หลีกเลี่ยงการเรนเดอร์ภาพทั้งหมดพร้อมกันเพื่อปรับปรุงเวลาในการโหลดหน้าเว็บ
- คล้ายกับแนวคิดของหน้าต่างที่กล่าวถึงก่อนหน้านี้ รูปภาพโหลดแบบขี้เกียจจะป้องกันการสร้างโหนด DOM ที่ไม่จำเป็น เพิ่มประสิทธิภาพของแอปพลิเคชัน React ของเรา
7. เหตุการณ์การควบคุมและการดีดกลับ
- การควบคุมปริมาณหมายถึงการชะลอการทำงานของฟังก์ชัน
- เค้นถูกเรียก มันจะทำงานของคุณเป็นระยะ ๆ ในขณะที่ debounce จะทำงานเพียงครั้งเดียวในตอนท้าย
- ตัวอย่างการควบคุม: การเลื่อนที่ไม่สิ้นสุด
- ตัวอย่าง Debounce: ค้นหาด้วยการโทร AJAX
8. คนทำงานเว็บ
JavaScript เป็นแอปพลิเคชันแบบเธรดเดียวเพื่อจัดการการดำเนินการซิงโครนัสทั้งหมด
ในขณะที่หน้าเว็บได้รับการแสดงผล จำเป็นต้องทำงานหลายอย่าง:
จัดการการโต้ตอบ UI, จัดการข้อมูลการตอบกลับ, จัดการองค์ประกอบ DOM, เปิดใช้งานแอนิเมชั่น ฯลฯ งานทั้งหมดเหล่านี้ได้รับการดูแลโดยเธรดเดียว
ผู้ปฏิบัติงานสามารถเห็นได้ว่าเป็นตัวเลือกในการลดภาระการดำเนินการในเธรดหลัก
เธรดผู้ปฏิบัติงานเป็นเธรดพื้นหลังที่ช่วยให้ผู้ใช้สามารถเรียกใช้หลายสคริปต์และการดำเนินการ JavaScript โดยไม่ขัดจังหวะเธรดหลัก
เมื่อใดก็ตามที่มีการดำเนินการงานที่ยาวนานซึ่งต้องการการใช้งาน CPU จำนวนมาก บล็อกแบบลอจิคัลเหล่านั้นสามารถดำเนินการบนเธรดแยกต่างหากโดยใช้ผู้ปฏิบัติงาน
จะวัดผลงานได้อย่างไร?
ตกลง เราเพิ่งพูดถึงการปรับปรุงประสิทธิภาพบางอย่าง แต่ถ้าเราต้องการวัด React Performance เราสามารถใช้เครื่องมือบางอย่างได้
1-) PageSpeed Insights
PageSpeed Insights เป็นเครื่องมือที่สร้างขึ้นโดย Google เพื่อให้ผู้คนสามารถระบุแนวทางปฏิบัติที่ดีที่สุดเกี่ยวกับประสิทธิภาพบนเว็บไซต์ใดๆ และรับคำแนะนำเกี่ยวกับการเพิ่มประสิทธิภาพที่สามารถใช้เพื่อทำให้เว็บไซต์นั้นเร็วขึ้น
ดังที่คุณเห็นภาพด้านบน เราสามารถตรวจสอบประสิทธิภาพเว็บของเราด้วยส่วนขยายLighthouse มันจะให้เมตริกบางอย่างสำหรับการใช้งานเดสก์ท็อปหรือมือถือ
2-) Profiler
วัดProfilerความถี่ที่แอปพลิเคชัน React แสดงผลและ "ต้นทุน" ของการเรนเดอร์คืออะไร จุดประสงค์คือเพื่อช่วยระบุส่วนต่างๆ ของแอปพลิเคชันที่ทำงานช้าและอาจได้ประโยชน์จากการปรับให้เหมาะสม เช่น การท่องจำ
การทำโปรไฟล์เพิ่มโอเวอร์ เฮดเพิ่มเติม ดังนั้นจึงปิดใช้งานในบิลด์การผลิต หากคุณต้องการใช้ในการผลิต คุณต้องใช้ Profiler API
เมื่อตัดสินใจใช้เทคนิคการเพิ่มประสิทธิภาพ รวมถึงการจำและโดยเฉพาะอย่างยิ่ง useCallback() ให้ทำดังนี้
1. โปรไฟล์
2. ประเมินประสิทธิภาพที่เพิ่มขึ้น (เช่น เพิ่มความเร็วในการเรนเดอร์ 150 มิลลิวินาทีเทียบกับ 50 มิลลิวินาที)
3. ถามตัวเองว่า: ประสิทธิภาพที่เพิ่มขึ้นเป็นอย่างไร เมื่อเทียบกับ
ความซับซ้อน ที่เพิ่มขึ้น , คุ้มค่ากับการใช้งาน useCallback() หรือไม่?
บทสรุป
เพื่อเพิ่มประสิทธิภาพแอปพลิเคชัน React ของเราให้ประสบความสำเร็จ ก่อนอื่นเราต้องค้นหาปัญหาประสิทธิภาพการทำงานในแอปพลิเคชันของเราเพื่อแก้ไข
สรุปสั้นๆ หากคุณมีปัญหากับประสิทธิภาพเว็บของคุณ คุณควรมองหาประสิทธิภาพที่ได้รับการปรับปรุง
เนื่องจากเมื่อคุณเริ่มโครงการใหม่และพยายามใช้เทคนิคประสิทธิภาพทั้งหมด โค้ดอาจซับซ้อนมากและประสบการณ์ของนักพัฒนาจะแย่เอามากๆ
ขอให้มีความสุขในการแฮ็ค ! :)
ติดตามฉันบน LinkedIn:https://www.linkedin.com/in/%C3%A7a%C4%9Flayan-yan%C4%B1ko%C4%9Flu-a6b42b13b/





































![รายการที่เชื่อมโยงคืออะไร? [ส่วนที่ 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)