เหตุใดแนวคิดของ React ของ Virtual DOM จึงมีประสิทธิภาพมากกว่าการตรวจสอบรุ่นที่สกปรก


372

ผมเห็นปฏิกิริยาพูดคุย dev ที่ ( พีทล่า: React: ทบทวนการปฏิบัติที่ดีที่สุด - JSConf สหภาพยุโรป 2013 ) และลำโพงที่กล่าวว่าสกปรกการตรวจสอบของรูปแบบได้ช้า แต่ไม่ได้คำนวณความแตกต่างระหว่าง DOM เสมือนจริงแม้จะมีประสิทธิภาพน้อยกว่าตั้งแต่ DOM เสมือนในกรณีส่วนใหญ่ควรมีขนาดใหญ่กว่าแบบจำลองใช่หรือไม่

ฉันชอบพลังที่อาจเกิดขึ้นของ Virtual DOM (โดยเฉพาะอย่างยิ่งการเรนเดอร์ฝั่งเซิร์ฟเวอร์) แต่ฉันต้องการทราบข้อดีและข้อเสียทั้งหมด


ฉันคิดว่าคุณสามารถพูดถึงการพูดคุยนี้ได้เช่นกันyoutube.com/watch?v=-DX3vJiqxm4ซึ่งเขาพูดถึงเรื่องการเปรียบเทียบเป็นพิเศษ
inafalcao

คำตอบ:


493

ฉันเป็นผู้เขียนหลักของโมดูลเสมือน - โดมดังนั้นฉันอาจตอบคำถามของคุณได้ ในความเป็นจริงมี 2 ปัญหาที่ต้องแก้ไขที่นี่

  1. ฉันจะแสดงผลอีกครั้งเมื่อใด คำตอบ: เมื่อฉันสังเกตเห็นว่าข้อมูลสกปรก
  2. ฉันจะแสดงผลใหม่ได้อย่างมีประสิทธิภาพได้อย่างไร คำตอบ: การใช้ DOM เสมือนเพื่อสร้าง patch จริง

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

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

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

DOM เสมือนเป็นสิ่งที่ดีเพราะมันช่วยให้เราสามารถเขียนโค้ดของเราราวกับว่าเรากำลังแสดงฉากทั้งหมด เบื้องหลังเราต้องการคำนวณการปะแก้ที่อัปเดต DOM เพื่อให้เป็นไปตามที่เราคาดหวัง ดังนั้นในขณะที่อัลกอริทึม DOM diff / patch เสมือนอาจไม่ใช่ทางออกที่ดีที่สุดแต่ก็เป็นวิธีที่ดีมากในการแสดงแอปพลิเคชันของเรา เราเพิ่งประกาศสิ่งที่เราต้องการอย่างแน่นอนและ React / virtual-dom จะหาวิธีทำให้ฉากของคุณเป็นแบบนี้ เราไม่จำเป็นต้องทำการจัดการ DOM ด้วยตนเองหรือสับสนเกี่ยวกับสถานะ DOM ก่อนหน้า เราไม่จำเป็นต้องแสดงภาพทั้งฉากอีกครั้งซึ่งอาจมีประสิทธิภาพน้อยกว่าการปะแก้


1
React ทำการตรวจสอบอุปกรณ์ประกอบฉากที่สกปรกหรือไม่? ฉันถามเพราะไม่มีฟังก์ชั่น setProps ()
bennlich


1
สิ่งที่จะเป็นตัวอย่างของการดังกล่าวunnecessary re-renders?
vsync

9
เมื่อคุณพูดว่า "ดังนั้นในขณะที่อัลกอริทึม DOM diff / patch เสมือนอาจไม่ใช่ทางออกที่ดีที่สุด" คุณมีคำตอบที่ดีที่สุดในทางทฤษฎีหรือไม่?
CMCDragonkai

3
ดูเหมือนจะตอบคำถามไม่ได้ React ต้องการให้คุณใช้ setState เพื่อส่งสัญญาณว่าสถานะมีการเปลี่ยนแปลง หากคุณสามารถทำได้this.state.cats = 99คุณจะต้องตรวจสอบสกปรกเพื่อตรวจสอบการเปลี่ยนแปลงรูปแบบเช่นเดียวกับที่ Angular สกปรกตรวจสอบต้นไม้ $ scope นี่ไม่ใช่การเปรียบเทียบความเร็วของทั้งสองเทคนิคมันเป็นเพียงคำสั่งที่ React ไม่ทำการตรวจสอบที่สกปรกเพราะมันมี setter ลักษณะของ Backbone แทน
superluminary

133

ฉันเพิ่งอ่านบทความรายละเอียดเกี่ยวกับขั้นตอนวิธีการตอบสนองความแตกต่างของที่นี่: http://calendar.perfplanet.com/2013/diff/ จากสิ่งที่ฉันเข้าใจสิ่งที่ทำให้ React รวดเร็วคือ:

  • การดำเนินการอ่าน / เขียน DOM เป็นกลุ่ม
  • อัพเดตที่มีประสิทธิภาพของทรีย่อยเท่านั้น

เมื่อเทียบกับการตรวจสอบที่สกปรกความแตกต่างที่สำคัญของ IMO คือ:

  1. ตัวแบบการตรวจสอบสกปรก : องค์ประกอบการทำปฏิกิริยาถูกกำหนดอย่างชัดเจนว่าสกปรกเมื่อใดก็ตามที่setStateมีการเรียกดังนั้นจึงไม่มีการเปรียบเทียบ (ของข้อมูล) ที่นี่ สำหรับการตรวจสอบที่สกปรกการเปรียบเทียบ (ของรุ่น) จะเกิดขึ้นในแต่ละวงย่อย

  2. การอัปเดต DOM : การทำงานของ DOM มีราคาแพงมากเนื่องจากการแก้ไข DOM จะใช้และคำนวณสไตล์ CSS, เลย์เอาต์ด้วย เวลาที่บันทึกจากการแก้ไข DOM ที่ไม่จำเป็นอาจนานกว่าเวลาที่ใช้ในการกระจาย DOM เสมือน

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


1
ที่จริงฉันได้อ่านบทความด้วยดังนั้นตอนนี้ (อย่างน้อยโดยทั่วไป) วิธีการทำงานฉันแค่อยากรู้ว่าทำไมมันถึงมีประสิทธิภาพมากกว่าการตรวจสอบแบบจำลองสกปรก และ 1) ใช่แล้วมันไม่ได้เปรียบเทียบแบบจำลอง แต่ทำการเปรียบเทียบแบบเสมือนที่ใหญ่กว่า 2) การตรวจสอบแบบจำลองสกปรกทำให้เราสามารถอัปเดตสิ่งที่จำเป็นได้เช่นกัน (ตามที่ Angular ทำ)
Daniil

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

1
การพูดของ Angular เนื่องจากผู้เฝ้าดูสามารถเปลี่ยนแปลงสถานะในขณะที่แยกย่อยได้ดังนั้น$scope.$digestจึงมีการดำเนินการหลายรอบต่อการแยกย่อยดังนั้นจึงเป็นการเปรียบเทียบข้อมูลเต็มเวลาหลายครั้งเมื่อเปรียบเทียบกับการเปรียบเทียบต้นไม้ DOM เสมือนบางส่วน
tungd

4
เป็นเรื่องน่าเศร้าที่นักพัฒนาสมาร์ทจำนวนมากคิดค้น "ภูเขา" ของกลอุบายเพื่อจัดการกับ DOM "ช้า" และอื่น ๆ แทนที่จะมุ่งเน้นความสนใจร่วมกันของเราเพียงแค่แก้ไขเบราว์เซอร์ด้วยตัวเองและกำจัดพวกเราออกจาก DOM ช้า มันเหมือนกับการใช้ทรัพยากรของมนุษยชาติทั้งหมดในการวิจัยวิธีการจัดการกับโรคมะเร็งและปรับปรุงชีวิตของผู้ป่วยแทนที่จะเพียงแค่แก้ไขมะเร็งเอง ridicules
vsync

@vsync DOM จำเป็นต้องแสดงเนื้อหาบนหน้าจอ DOM เสมือนไม่ได้ แม้จะมี DOM ที่มีประสิทธิภาพดีเยี่ยม แต่การสร้าง DOM เสมือนก็จะเร็ว
Jehan

75

ฉันชอบพลังที่อาจเกิดขึ้นของ Virtual DOM (โดยเฉพาะอย่างยิ่งการเรนเดอร์ฝั่งเซิร์ฟเวอร์) แต่ฉันต้องการทราบข้อดีและข้อเสียทั้งหมด

- OP

React ไม่ใช่ไลบรารีการจัดการ DOM เท่านั้น ฉันขอแนะนำให้คุณทำความเข้าใจกับทางเลือกอื่นโดยการอ่านบทความนี้จาก Auth0ซึ่งมีคำอธิบายโดยละเอียดและมาตรฐาน ฉันจะเน้นที่นี่ข้อดีและข้อเสียของพวกเขาที่คุณถาม:

React.js 'DOM เสมือน

ป้อนคำอธิบายรูปภาพที่นี่

ข้อดี

  • อัลกอริทึม "diffing" ที่รวดเร็วและมีประสิทธิภาพ
  • หลายส่วนหน้า (JSX, hyperscript)
  • เบาพอที่จะทำงานบนอุปกรณ์พกพา
  • แรงฉุดและความคิดมากมาย
  • สามารถใช้ได้โดยไม่ต้องทำปฏิกิริยา (เช่นเป็นเอ็นจิ้นอิสระ)

ข้อเสีย

  • สำเนาในหน่วยความจำเต็มของ DOM (ใช้หน่วยความจำสูงกว่า)
  • ไม่มีความแตกต่างระหว่างองค์ประกอบแบบคงที่และแบบไดนามิก

Ember.js 'Glimmer

ป้อนคำอธิบายรูปภาพที่นี่

ข้อดี

  • อัลกอริธึมการกระจายที่รวดเร็วและมีประสิทธิภาพ
  • ความแตกต่างระหว่างองค์ประกอบแบบคงที่และแบบไดนามิก
  • เข้ากันได้ 100% กับ API ของ Ember (คุณจะได้รับสิทธิประโยชน์โดยไม่มีการอัปเดตโค้ดที่มีอยู่ของคุณ)
  • การเป็นตัวแทนเบาในหน่วยความจำของ DOM

ข้อเสีย

  • หมายถึงใช้เฉพาะใน Ember
  • มีส่วนหน้าเดียวเท่านั้น

DOM ที่เพิ่มขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

ข้อดี

  • การใช้งานหน่วยความจำลดลง
  • API อย่างง่าย
  • รวมเข้ากับส่วนหน้าและเฟรมเวิร์กได้ง่าย ๆ (หมายถึงเทมเพลตเอนจินของเครื่องยนต์ตั้งแต่ต้น)

ข้อเสีย

  • ไม่เร็วเท่ากับห้องสมุดอื่น ๆ (สามารถโต้แย้งได้ดูมาตรฐานด้านล่าง)
  • การใช้ความคิดและชุมชนน้อยลง

การเป็นตัวแทนของการจัดการ DOM ของ ReactJS นั้นดูเหมือนจะไม่สำคัญสำหรับฉัน ReactJS เสมือนของ DOM เป็นสิ่งที่เปลี่ยนแปลงไปอย่างสิ้นเชิงไม่ใช่ DOM จริงๆ - ถูกต้องไหม? ฉันกำลังมองหาที่บทความต้นฉบับอ้างอิงอ้างอิงบทความและนี่คือสิ่งที่ฉันเห็น - teropa.info/images/onchange_vdom_change.svg teropa.info/blog/2015/03/02/…
smile.al.d.way

35

นี่คือความคิดเห็นโดย React สมาชิกในทีม Sebastian Markbågeที่ให้ความกระจ่าง:

React ทำ diffing บนเอาท์พุท (ซึ่งเป็นฟอร์แมตที่รู้จักกันในชื่อแอตทริบิวต์ DOM) ซึ่งหมายความว่าข้อมูลต้นฉบับสามารถเป็นรูปแบบใดก็ได้ สามารถเป็นโครงสร้างข้อมูลที่ไม่เปลี่ยนแปลงและสถานะภายในการปิด

โมเดลเชิงมุมไม่ได้รักษาความโปร่งใสในการอ้างอิงดังนั้นจึงไม่แน่นอน คุณเปลี่ยนรูปแบบที่มีอยู่เพื่อติดตามการเปลี่ยนแปลง ถ้าแหล่งข้อมูลของคุณเป็นข้อมูลที่ไม่เปลี่ยนรูปแบบหรือโครงสร้างข้อมูลใหม่ทุกครั้ง (เช่นการตอบสนอง JSON)

การตรวจสอบสกปรกและ Object.observe ไม่ทำงานกับสถานะขอบเขตการปิด

สองสิ่งนี้มีข้อ จำกัด อย่างมากต่อรูปแบบการทำงาน

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

https://news.ycombinator.com/item?id=6937668


2
อันที่จริงเกี่ยวกับย่อหน้าสุดท้าย: มันควรจะผิด: model ใหญ่กว่า virtual dom เพราะสำหรับแต่ละ model model จะมี (ในกรณีส่วนใหญ่) อย่างน้อยหนึ่งองค์ประกอบ dom เสมือนจริง (และมักจะมากกว่าหนึ่ง) ทำไมฉันถึงต้องการรุ่นที่ไม่แสดง
Daniil

2
กำลังสร้างการเก็บแคช
kentor

-2

Virtual Dom ไม่ได้ถูกประดิษฐ์โดยปฏิกิริยา มันเป็นส่วนหนึ่งของ HTML มันมีน้ำหนักเบาและแยกออกจากรายละเอียดการใช้งานเฉพาะเบราว์เซอร์

เราสามารถคิดว่า DOM เสมือนเป็นสำเนาเฉพาะที่ของ Local React และเรียบง่ายของ HTML DOM อนุญาตให้ React ทำการคำนวณภายในโลกนามธรรมนี้และข้ามการดำเนินงาน DOM "ของจริง" ซึ่งมักจะช้าและเฉพาะเบราว์เซอร์ จริงๆแล้วไม่มีความแตกต่างใหญ่ระหว่าง DOM และ VIRTUAL DOM

ด้านล่างนี้เป็นจุดที่ใช้ Virtual Dom (แหล่งที่มาของDOM เสมือนใน ReactJS ):

เมื่อคุณทำ:

document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
  1. เบราว์เซอร์จำเป็นต้องแยกวิเคราะห์ HTML
  2. มันลบองค์ประกอบลูกของ elementId
  3. อัพเดตค่า DOM ด้วยค่าใหม่
  4. คำนวณ css อีกครั้งสำหรับผู้ปกครองและเด็ก
  5. อัปเดตเลย์เอาต์เช่นองค์ประกอบแต่ละอย่างที่ตรงกันบนหน้าจอ
  6. ข้ามแผนผังเรนเดอร์และทาสีบนจอแสดงผลของเบราว์เซอร์

การคำนวณใหม่ CSS และโครงร่างที่เปลี่ยนแปลงใช้อัลกอริธึมที่ซับซ้อนและส่งผลต่อประสิทธิภาพ

รวมถึงการอัพเดทคุณสมบัติ DOM เช่น ค่า มันเป็นไปตามอัลกอริทึม

ทีนี้สมมติว่าถ้าคุณอัปเดต DOM 10 ครั้งโดยตรงจากนั้นขั้นตอนข้างต้นทั้งหมดจะทำงานทีละขั้นตอนและการอัปเดตอัลกอริทึม DOM จะใช้เวลาในการอัปเดตค่า DOM

นี่คือเหตุผลที่ DOM จริงช้ากว่า DOM เสมือน


3
เกี่ยวกับตัวอย่างถ้าคุณกำลังแก้ไข dom โดยตรงหรือผ่าน virtual dom ในที่สุดสำหรับทั้งสองกรณีคุณกำลังเปลี่ยน dom
magallanes

ใช่ในทั้งสองกรณีเรากำลังปรับปรุง dom แต่ในกรณีของ dom เสมือนมันจะอัปเดตเฉพาะที่สำคัญฟิลด์ (กำหนดโดยไม่ซ้ำกันโดยอัลกอริทึมจากปฏิกิริยา) หรือแท็กองค์ประกอบเท่านั้น ในขณะที่การอัพเดตอัพเดท Dom หรือรีเฟรชทั้ง Dom อย่างสมบูรณ์
Hemant Nagarkoti

11
ฉันได้เห็นบทความนี้จากhackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130 อาจเป็นการดีกว่าที่จะชี้แหล่งที่มาหากคุณไม่ใช่ผู้เขียน
Jinggang

2
"นี่คือเหตุผลที่ DOM จริงช้ากว่า DOM เสมือน" ไม่ครับคุณเป็นคนผิด
Roecrew
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.