นับตั้งแต่เปิดตัวครั้งแรก React ได้เปลี่ยนความคิดของนักพัฒนาส่วนหน้าเมื่อสร้างเว็บแอปพลิเคชัน ด้วย Virtual DOM React ทำให้การอัปเดต UI (ส่วนต่อประสานผู้ใช้) มีประสิทธิภาพเช่นเคยในขณะที่ทำให้เว็บแอปพลิเคชันของคุณแม่นยำยิ่งขึ้น แต่ทำไมเว็บแอป React ที่มีขนาดพอเหมาะยังทำงานได้ไม่ดี
ที่สำคัญคือคุณใช้ React อย่างไร
ห้องสมุดส่วนหน้าที่ทันสมัยเช่น ตอบสนอง มันไม่ได้ทำให้แอปของคุณเร็วขึ้นอย่างน่าอัศจรรย์ นักพัฒนาจำเป็นต้องเข้าใจวิธีการทำงานของ React และการทำงานของส่วนประกอบผ่านขั้นตอนต่างๆของวงจรชีวิตของส่วนประกอบ
ด้วย React คุณจะได้รับการปรับปรุงมากมายที่มีให้โดยการวัดและปรับแต่งว่าส่วนประกอบของคุณส่งคืนอย่างไรและเมื่อใด และ React มีเพียงเครื่องมือและฟังก์ชันที่จำเป็นเพื่อให้ง่ายขึ้น
ในบทช่วยสอน React นี้คุณจะได้เรียนรู้วิธีวัดประสิทธิภาพของส่วนประกอบ React ของคุณและปรับแต่งให้เหมาะสมเพื่อสร้างเว็บแอปพลิเคชัน React ที่สูงขึ้นและมีประสิทธิภาพดีขึ้น ในทำนองเดียวกันคุณจะได้เรียนรู้ว่าแนวทางปฏิบัติที่ดีที่สุดสองประการของ JavaScript ยังช่วยให้เว็บแอปพลิเคชัน React ของคุณนำเสนอประสบการณ์ผู้ใช้ที่ราบรื่นได้อย่างไร
ก่อนที่เราจะเข้าสู่เทคนิคการเพิ่มประสิทธิภาพเราจำเป็นต้องเข้าใจวิธีการทำงานของ React ให้ดีขึ้น
หัวใจสำคัญของ React คือไวยากรณ์ JSX และความสามารถของ React ในการสร้างและเปรียบเทียบ DOM เสมือน . นับตั้งแต่เปิดตัว React มีอิทธิพลต่อไลบรารีฟรอนต์เอนด์อื่น ๆ อีกมากมาย ไลบรารีเช่น Vue.js ยังอาศัยแนวคิดของ DOM เสมือน
นี่คือวิธีการทำงานของ React:
ทุกแอปพลิเคชัน React เริ่มต้นด้วยส่วนประกอบของรูทและประกอบด้วยส่วนประกอบหลายอย่างในการสร้างต้นไม้ ส่วนประกอบใน React คือ 'ฟังก์ชัน' ที่ออกจาก UI ตามข้อมูล (การสนับสนุนและสถานะ) ที่ได้รับ
เราสามารถใช้สัญลักษณ์นี้เป็น F
UI = F(data)
ผู้ใช้โต้ตอบกับ UI และทำให้เกิดการเปลี่ยนแปลงข้อมูล ไม่ว่าการโต้ตอบจะเป็นการคลิกปุ่มแตะรูปภาพลากรายการจากรายการ AJAX ร้องขอที่เรียก API ฯลฯ การโต้ตอบทั้งหมดจะเปลี่ยนข้อมูลเท่านั้น พวกเขาไม่เคยทำให้ UI เปลี่ยนแปลงโดยตรง
ที่นี่ข้อมูลคือทุกสิ่งที่กำหนดสถานะของเว็บแอปพลิเคชันไม่ใช่เฉพาะสิ่งที่คุณเก็บไว้ในฐานข้อมูลของคุณ แม้แต่ส่วนของสถานะส่วนหน้า (เช่นหน้าต่างใดที่ถูกเลือกในขณะนี้หรือหากมีการเลือกช่องในขณะนี้) ก็เป็นส่วนหนึ่งของข้อมูลนี้
เมื่อมีการเปลี่ยนแปลงในข้อมูลนี้ React จะใช้ฟังก์ชันคอมโพเนนต์เพื่อออกจาก UI อีกครั้ง แต่แทบจะ:
UI1 = F(data1) UI2 = F(data2)
React จะคำนวณความแตกต่างระหว่าง UI ปัจจุบันและ UI ใหม่โดยใช้อัลกอริธึมเปรียบเทียบกับ DOM เสมือนทั้งสองเวอร์ชันของคุณ
อะไรเป็นประกายดีสำหรับ
Changes = Diff(UI1, UI2)
ตอบสนองจากนั้นดำเนินการต่อเพื่อใช้เฉพาะการเปลี่ยนแปลงกับ UI จริงในเบราว์เซอร์
เมื่อข้อมูลที่เกี่ยวข้องกับคอมโพเนนต์เปลี่ยนแปลง React จะพิจารณาว่าจำเป็นต้องมีการอัปเดต DOM หรือไม่ สิ่งนี้ช่วยให้ React หลีกเลี่ยงการดำเนินการจัดการ DOM ที่มีราคาแพงในเบราว์เซอร์เช่นการสร้างโหนด DOM และการเข้าถึงโหนดที่มีอยู่บางส่วนเกินความจำเป็น
การคำนวณความแตกต่างซ้ำ ๆ และการทิ้งส่วนประกอบอาจเป็นหนึ่งในแหล่งที่มาหลักของปัญหาประสิทธิภาพของ React ในแอปพลิเคชัน React ใด ๆ การสร้างแอปพลิเคชัน React ซึ่งไม่สามารถปรับความแตกต่างของอัลกอริทึมได้อย่างมีประสิทธิภาพจึงทำให้แอปพลิเคชันทั้งหมดถูกทิ้งซ้ำ ๆ อาจส่งผลให้เกิดประสบการณ์ที่น่าผิดหวังและใช้เวลานาน
แต่เรากำลังเพิ่มประสิทธิภาพอะไรกันแน่?
ในระหว่างกระบวนการเริ่มต้นของการละทิ้ง React จะสร้างทรี DOM ดังนี้:
เนื่องจากข้อมูลบางส่วนมีการเปลี่ยนแปลงสิ่งที่เราต้องการให้ React ทำคือการย้อนกลับเฉพาะส่วนประกอบที่ได้รับผลกระทบโดยตรงจากการเปลี่ยนแปลง (และอาจข้ามขั้นตอนที่แตกต่างไปสำหรับส่วนประกอบที่เหลือ):
อย่างไรก็ตามสิ่งที่ React ทำคือ:
ในภาพด้านบนโหนดสีเหลืองทั้งหมดจะแสดงผลและสร้างความแตกต่าง (แตกต่าง) ทำให้เสียเวลาในการคำนวณ / ทรัพยากร นี่คือจุดที่เราจะใช้ความพยายามในการเพิ่มประสิทธิภาพเป็นหลัก การตั้งค่าแต่ละองค์ประกอบให้เฉพาะการแสดงผล - สร้างความแตกต่าง (แตกต่าง) เมื่อจำเป็นจะช่วยให้เราสามารถกู้คืนวงจร CPU ที่หายไปเหล่านี้ได้
นามสกุลไฟล์ c++
นักพัฒนาของไลบรารี React ได้คำนึงถึงสิ่งนี้และจัดหาเบ็ดเพื่อให้เราสามารถทำสิ่งนั้นได้: ฟังก์ชันที่ช่วยให้เราสามารถบอก React ได้เมื่อสามารถข้ามการเรนเดอร์ของคอมโพเนนต์ได้
อย่างที่ Rob Pike ทำให้มันเป็นหนึ่งใน กฎการตั้งเวลา :
ถึงขนาด อย่าปรับความเร็วจนกว่าคุณจะวัดได้และถึงแม้จะไม่ทำเว้นแต่ส่วนหนึ่งของโค้ดจะบังส่วนที่เหลือ
อย่าเพิ่มประสิทธิภาพโค้ดที่คุณคิดว่าอาจทำให้แอปพลิเคชันของคุณช้าลง ให้เครื่องมือวัดประสิทธิภาพของ React ช่วยแนะนำคุณตลอดเส้นทาง
React มี เครื่องมือที่แข็งแกร่ง สำหรับสิ่งนี้. เมื่อใช้ react-addons-perf
คุณจะได้รับข้อมูลสรุปเกี่ยวกับประสิทธิภาพโดยรวมของแอปพลิเคชันของคุณ
การใช้งานนั้นง่ายมาก:
Import Perf from 'react-addons-perf' Perf.start(); // use the app Perf.stop(); Perf.printWasted();
การดำเนินการนี้จะพิมพ์ตารางที่มีส่วนประกอบของเวลาที่สูญเสียไปเมื่อแสดงผล
ไลบรารีมีฟังก์ชันอื่น ๆ ที่ช่วยให้คุณสามารถพิมพ์แง่มุมต่างๆของเวลาที่เสียไปโดยแยกจากกัน (เช่นการใช้ฟังก์ชัน printInclusive()
หรือ printExclusive()
) หรือแม้แต่พิมพ์การดำเนินการจัดการ DOM (โดยใช้ printOperations()
) .
ถ้าคุณเป็นคนชอบมองเห็นแล้ว react-perf-tool
คือสิ่งที่คุณต้องการ
react-perf-tool
มันขึ้นอยู่กับไลบรารี react-addons-perf
ช่วยให้คุณเห็นภาพมากขึ้นในการแก้ไขข้อบกพร่องประสิทธิภาพของแอปพลิเคชันของคุณด้วย React ใช้ไลบรารีพื้นฐานเพื่อรับการวัดจากนั้นแสดงเป็นกราฟ
บ่อยครั้งนี่เป็นวิธีที่สะดวกกว่ามากในการสังเกตแถบ คุณสามารถใช้งานได้อย่างง่ายดายโดยเพิ่มเป็นส่วนประกอบในแอปพลิเคชันของคุณ
โดยค่าเริ่มต้น React จะทำงานแสดงผล DOM เสมือนและเปรียบเทียบความแตกต่างของแต่ละองค์ประกอบในโครงสร้างสำหรับการเปลี่ยนแปลงแต่ละอย่างในอุปกรณ์ประกอบฉากและสถานะ แต่นั่นไม่ใช่เหตุผลอย่างเห็นได้ชัด
เมื่อแอปพลิเคชันของคุณเติบโตขึ้นการพยายามแสดงผลซ้ำและเปรียบเทียบ DOM เสมือนทั้งหมดในทุกการกระทำจะช้าลงในที่สุด
React เป็นวิธีง่ายๆสำหรับนักพัฒนาในการระบุว่าจำเป็นต้องแสดงผลส่วนประกอบใหม่หรือไม่ นี่คือที่ shouldComponentUpdate
เข้ามาเล่น
aws ได้รับการรับรอง โซลูชั่น สถาปนิก ใบรับรอง
function shouldComponentUpdate(nextProps, nextState) { return true; }
เมื่อฟังก์ชันนี้คืนค่าเป็นจริงสำหรับส่วนประกอบใด ๆ ฟังก์ชันนี้จะอนุญาตให้ทริกเกอร์กระบวนการสร้างความแตกต่างของการแสดงผล
วิธีนี้ช่วยให้คุณควบคุมกระบวนการสร้างความแตกต่างในการแสดงผลได้อย่างง่ายดาย เมื่อคุณต้องการป้องกันไม่ให้คอมโพเนนต์ถูกแสดงซ้ำโดยสมบูรณ์มันเป็นเพียงผลลัพธ์ falso
ของฟังก์ชัน ภายในฟังก์ชั่นคุณสามารถเปรียบเทียบชุดของการสนับสนุนและสถานะปัจจุบันรวมทั้งข้อมูลต่อไปนี้เพื่อพิจารณาว่าจำเป็นต้องมีการเรนเดอร์หรือไม่:
function shouldComponentUpdate(nextProps, nextState) { return nextProps.id !== this.props.id; }
เพื่อให้เทคนิคการเพิ่มประสิทธิภาพนี้ง่ายขึ้นและเป็นแบบอัตโนมัติมากขึ้น React จะให้สิ่งที่เรียกว่าส่วนประกอบ 'บริสุทธิ์' ก React.PureComponent
เหมือนกับ React.Component
ที่ใช้ฟังก์ชัน shouldComponentUpdate()
ด้วยการเปรียบเทียบการสนับสนุนและสถานะที่ว่างเปล่า
ก React.PureComponent
เทียบเท่ากับสิ่งนี้โดยประมาณ:
class MyComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this.props, nextProps) && shallowCompare(this.state, nextState); } … }
เนื่องจากจะทำการเปรียบเทียบที่ว่างเปล่าเท่านั้นคุณอาจพบว่ามีประโยชน์ก็ต่อเมื่อ:
forceUpdate()
เพื่ออัปเดตส่วนประกอบของคุณจะเป็นอย่างไรถ้าคุณสามารถใช้ React.PureComponent
และยังมีวิธีที่มีประสิทธิภาพในการดูว่าการสนับสนุนหรือสถานะที่ซับซ้อนมีการเปลี่ยนแปลงโดยอัตโนมัติหรือไม่? นี่คือที่โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปทำให้ชีวิตง่ายขึ้นสำหรับเรา
แนวคิดเบื้องหลังการใช้โครงสร้างข้อมูลที่ไม่เปลี่ยนรูปเป็นเรื่องง่าย เมื่ออ็อบเจ็กต์ที่มีข้อมูลซับซ้อนเปลี่ยนแปลงแทนที่จะทำการเปลี่ยนแปลงกับอ็อบเจ็กต์นั้นจะสร้างสำเนาของอ็อบเจ็กต์นั้นพร้อมกับการเปลี่ยนแปลง สิ่งนี้ทำให้การตรวจจับการเปลี่ยนแปลงข้อมูลทำได้ง่ายเพียงแค่เปรียบเทียบการอ้างอิงของวัตถุทั้งสอง
คุณสามารถใช้ Object.assign
หรือ _.extend
(จาก Underscore.js หรือ Lodash):
const newValue2 = Object.assign({}, oldValue); const newValue2 = _.extend({}, oldValue);
ยิ่งไปกว่านั้นคุณสามารถใช้ไลบรารีที่จัดเตรียมโครงสร้างข้อมูลที่ไม่เปลี่ยนรูปได้:
var map1 = Immutable.Map({a:1, b:2, c:3}); var map2 = map1.set('b', 2); assert(map1.equals(map2) === true); var map3 = map1.set('b', 50); assert(map1.equals(map3) === false);
ที่นี่ Immutable.Map
จัดทำโดยห้องสมุด ไม่เปลี่ยนรูป js .
ทุกครั้งที่มีการอัปเดตแผนที่ด้วยเมธอด set
แผนที่ใหม่จะถูกส่งคืนเฉพาะเมื่อการดำเนินการตั้งค่าเปลี่ยนค่าพื้นฐาน มิฉะนั้นแผนที่เดิมจะถูกส่งกลับ
หลักการเกสตัลต์ขององค์กร
คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการใช้โครงสร้างข้อมูลที่ไม่เปลี่ยนรูป ที่นี่ .
เมื่อคุณพัฒนาแอปพลิเคชันด้วย React คุณจะได้รับคำเตือนและข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์มาก สิ่งเหล่านี้ทำให้การระบุจุดบกพร่องและปัญหาระหว่างการพัฒนาทำได้ง่ายมาก แต่ก็มีค่าใช้จ่ายในการแสดงเช่นกัน
หากคุณดูที่ซอร์สโค้ด React คุณจะเห็นเครื่องหมาย if (process.env.NODE_ENV != 'production')
จำนวนมาก โค้ดเหล่านี้ที่ React ทำงานในสภาพแวดล้อมการพัฒนาของคุณไม่ใช่สิ่งที่ผู้ใช้ต้องการ สำหรับสภาพแวดล้อมการใช้งานจริงรหัสที่ไม่จำเป็นทั้งหมดนี้สามารถทิ้งได้
หากคุณผลักดันโครงการของคุณโดยใช้ create-react-app
คุณสามารถเรียกใช้ npm run build
เพื่อสร้างงานสร้างโดยไม่มีรหัสพิเศษนี้ หากคุณใช้ Webpack โดยตรงคุณสามารถเรียกใช้ webpack -p
(ซึ่งเทียบเท่ากับ webpack --optimize-minimize --define process.env.NODE_ENV=''production''
.
เป็นเรื่องปกติมากที่จะเห็นฟังก์ชันที่เชื่อมโยงกับบริบทของส่วนประกอบภายในฟังก์ชันที่แสดงผล ซึ่งมักจะเกิดขึ้นเมื่อเราใช้ฟังก์ชันเหล่านี้เพื่อจัดการกับเหตุการณ์ของส่วนประกอบในระยะเริ่มต้น
// Creates a new `handleUpload` function during each render() // ...as do inlined arrow functions this.handleUpload(files)} />
ซึ่งจะทำให้เกิด render()
สร้างฟังก์ชันใหม่ในการเรนเดอร์แต่ละครั้ง วิธีที่ดีกว่าในการทำเช่นเดียวกันคือ:
class App extends React.Component { constructor(props) { super(props); this.handleUpload = this.handleUpload.bind(this); } render() { … … } }
สำหรับเว็บแอป React แบบหน้าเดียวโดยทั่วไปเราจะรวมโค้ด JavaScript ส่วนหน้าทั้งหมดไว้ในไฟล์ที่ย่อขนาดไฟล์เดียว ใช้งานได้ดีสำหรับเว็บแอปพลิเคชันขนาดกลาง แต่ในขณะที่แอปพลิเคชันเริ่มเติบโตขึ้นการส่งไฟล์ JavaScript ที่แนบมากับเบราว์เซอร์อาจเป็นกระบวนการที่ใช้เวลานานมาก
หากคุณใช้ Webpack เพื่อสร้างแอปพลิเคชันของคุณคุณสามารถเพิ่มรหัสของคุณได้โดยแยกความสามารถของมันเพื่อแยกรหัสแอปพลิเคชันที่สร้างขึ้นของคุณออกเป็น 'กลุ่ม' หลาย ๆ ชิ้นและส่งไปยังเบราว์เซอร์ตามเวลาที่จำเป็น
การแยกมีสองประเภท ได้แก่ การแยกทรัพยากรและการแยกรหัสตามความต้องการ
ด้วยการแยกทรัพยากรคุณสามารถแยกเนื้อหาทรัพยากรออกเป็นหลายไฟล์ ตัวอย่างเช่นโดยใช้ CommonsChunkPlugin คุณสามารถแยกโค้ดทั่วไป (เช่นไลบรารีภายนอกทั้งหมด) ไปยังไฟล์กลุ่มที่เหมาะสม โดยใช้ ExtractTextWebpackPlugin คุณสามารถแยกโค้ด CSS ทั้งหมดไปยังไฟล์ CSS แยกกันได้
การแยกประเภทนี้จะช่วยคุณได้สองทาง ช่วยให้เครื่องมือค้นหาจัดเก็บทรัพยากรเหล่านั้นที่มีการเปลี่ยนแปลงน้อยลง นอกจากนี้ยังช่วยให้ผู้ค้นหาใช้ประโยชน์จากการดาวน์โหลดคู่ขนานเพื่อลดเวลาในการโหลด
คุณสมบัติที่โดดเด่นกว่าของ Webpack คือการแยกรหัสตามความต้องการ วิธีนี้สามารถทำให้การดาวน์โหลดครั้งแรกมีขนาดเล็กโดยลดเวลาในการโหลดแอปพลิเคชัน ดังนั้นเบราว์เซอร์สามารถดาวน์โหลดโค้ดตามต้องการเมื่อแอปพลิเคชันต้องการ
คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการแยกรหัส Webpack ที่นี่ .
รวมไว้ใน c++
กลุ่มของไฟล์ JS ของแอปพลิเคชัน React มักมีขนาดใหญ่มากดังนั้นเพื่อให้โหลดหน้าเว็บได้เร็วขึ้นเราสามารถเปิดใช้งาน Gzip บนเว็บเซิร์ฟเวอร์ (Apache, Nginx ฯลฯ )
เครื่องมือค้นหาสมัยใหม่ทั้งหมดสนับสนุนและเจรจาการบีบอัด Gzip สำหรับคำขอ HTTP โดยอัตโนมัติ การเปิดใช้งานการบีบอัด Gzip สามารถลดขนาดของการตอบกลับที่โอนได้ 90% ซึ่งสามารถลดระยะเวลาในการดาวน์โหลดทรัพยากรลดการใช้ข้อมูลสำหรับไคลเอ็นต์และปรับปรุงเวลาในการแสดงผลเพจของคุณ
ตรวจสอบเอกสารสำหรับเว็บเซิร์ฟเวอร์ของคุณเพื่อดูวิธีเปิดใช้งานการบีบอัด:
คุณควรใช้ ESLint สำหรับโครงการ JavaScript เกือบทั้งหมด ปฏิกิริยาไม่ใช่ความแตกต่าง
ด้วย eslint-plugin-react
คุณจะต้องบังคับตัวเองให้ปรับตัวเข้ากับกฎการเขียนโปรแกรมของ React ซึ่งจะเป็นประโยชน์ต่อโค้ดของคุณในระยะยาวและหลีกเลี่ยงปัญหาทั่วไปและความไม่สะดวกมากมายที่เกิดขึ้นเนื่องจากการเขียนโค้ดที่ไม่ดี
เพื่อให้ได้รับประโยชน์สูงสุดจาก React คุณต้องใช้ประโยชน์จากเครื่องมือและเทคนิคต่างๆ ประสิทธิภาพของเว็บแอปพลิเคชัน React อยู่ที่ความเรียบง่ายของส่วนประกอบ การใช้อัลกอริธึมการสร้างความแตกต่างและการแสดงผลที่มากเกินไปอาจทำให้แอปพลิเคชันของคุณทำงานได้ไม่ดีจนน่าหงุดหงิด
ก่อนที่คุณจะสามารถเพิ่มประสิทธิภาพแอปพลิเคชันของคุณคุณต้องเข้าใจว่าส่วนประกอบของ React ทำงานอย่างไรและแสดงผลอย่างไรในเบราว์เซอร์ของคุณ วิธีวงจรชีวิตของ React ให้วิธีป้องกันไม่ให้คอมโพเนนต์ของคุณแสดงผลซ้ำโดยไม่จำเป็น ขจัดอุปสรรคเหล่านั้นและคุณจะมีประสิทธิภาพแอปพลิเคชันที่ผู้ใช้ของคุณสมควรได้รับ
แม้ว่าจะมีหลายวิธีในการเพิ่มประสิทธิภาพเว็บแอปพลิเคชันด้วย React แต่การปรับแต่งส่วนประกอบเพื่ออัปเดตเมื่อจำเป็นเท่านั้นที่ป้องกันไม่ให้ปรับปรุงประสิทธิภาพ
คุณวัดและเพิ่มประสิทธิภาพเว็บแอปพลิเคชันของคุณด้วย React ได้อย่างไร? แบ่งปันในความคิดเห็นด้านล่าง