Tại sao khái niệm Virtual DOM của React được cho là hiệu quả hơn so với kiểm tra mô hình bẩn?


372

Tôi đã thấy một nhà phát triển React tại ( Pete Hunt: React: Xem xét lại các thực tiễn tốt nhất - JSConf EU 2013 ) và diễn giả đã đề cập rằng việc kiểm tra mô hình bẩn có thể bị chậm. Nhưng không tính được sự khác biệt giữa các DOM ảo thực sự thậm chí còn kém hiệu quả hơn vì DOM ảo, trong hầu hết các trường hợp, nên lớn hơn mô hình?

Tôi thực sự thích sức mạnh tiềm tàng của Virtual DOM (đặc biệt là kết xuất phía máy chủ) nhưng tôi muốn biết tất cả các ưu và nhược điểm.


Tôi nghĩ bạn có thể đề cập đến cuộc nói chuyện này quá youtube.com/watch?v=-DX3vJiqxm4 nơi anh ấy đặc biệt nói về điểm chuẩn.
inafalcao

Câu trả lời:


493

Tôi là tác giả chính của mô-đun ảo , vì vậy tôi có thể trả lời câu hỏi của bạn. Thực tế có 2 vấn đề cần được giải quyết ở đây

  1. Khi nào tôi kết xuất lại? Trả lời: Khi tôi quan sát thấy dữ liệu bị bẩn.
  2. Làm thế nào để tôi kết xuất lại hiệu quả? Trả lời: Sử dụng DOM ảo để tạo bản vá DOM thực

Trong React, mỗi thành phần của bạn có một trạng thái. Trạng thái này giống như một trạng thái có thể quan sát mà bạn có thể tìm thấy trong các thư viện loại trực tiếp hoặc MVVM khác. Về cơ bản, React biết khi nào sẽ kết xuất lại cảnh vì nó có thể quan sát khi dữ liệu này thay đổi. Kiểm tra bẩn chậm hơn các quan sát vì bạn phải thăm dò dữ liệu theo một khoảng thời gian đều đặn và kiểm tra tất cả các giá trị trong cấu trúc dữ liệu theo cách đệ quy. Khi so sánh, việc đặt giá trị trên trạng thái sẽ báo hiệu cho người nghe biết rằng một số trạng thái đã thay đổi, vì vậy React có thể chỉ cần lắng nghe các sự kiện thay đổi trên trạng thái và xếp hàng kết xuất lại.

DOM ảo được sử dụng để kết xuất lại DOM hiệu quả. Điều này không thực sự liên quan đến việc kiểm tra dữ liệu bẩn của bạn. Bạn có thể kết xuất lại bằng DOM ảo có hoặc không có kiểm tra bẩn. Bạn đúng ở chỗ có một số chi phí trong việc tính toán độ lệch giữa hai cây ảo, nhưng khác biệt DOM ảo là về việc hiểu những gì cần cập nhật trong DOM và không biết liệu dữ liệu của bạn có thay đổi hay không. Trong thực tế, thuật toán diff là bản thân trình kiểm tra bẩn nhưng nó được sử dụng để xem liệu DOM có bị bẩn không.

Chúng tôi chỉ nhắm mục tiêu kết xuất lại cây ảo khi trạng thái thay đổi. Vì vậy, sử dụng một quan sát để kiểm tra xem trạng thái đã thay đổi hay chưa là một cách hiệu quả để ngăn chặn việc tái xuất không cần thiết, điều này sẽ gây ra nhiều khác biệt về cây không cần thiết. Nếu không có gì thay đổi, chúng tôi không làm gì cả.

Một DOM ảo là tốt vì nó cho phép chúng ta viết mã của mình như thể chúng ta đang hiển thị lại toàn bộ cảnh. Đằng sau hậu trường, chúng tôi muốn tính toán một hoạt động vá lỗi cập nhật DOM để xem chúng tôi mong đợi như thế nào. Vì vậy, trong khi thuật toán diff / patch DOM ảo có lẽ không phải là giải pháp tối ưu , nó mang lại cho chúng ta một cách rất hay để thể hiện các ứng dụng của mình. Chúng tôi chỉ tuyên bố chính xác những gì chúng tôi muốn và React / virtual-dom sẽ tìm ra cách làm cho cảnh của bạn trông như thế này. Chúng ta không phải thực hiện thao tác DOM thủ công hoặc nhầm lẫn về trạng thái DOM trước đó. Chúng ta cũng không phải kết xuất lại toàn bộ cảnh, điều này có thể kém hiệu quả hơn nhiều so với vá nó.


1
React có kiểm tra bẩn trên đạo cụ thành phần không? Tôi hỏi vì không có hàm setProps ().
bennlich


1
Điều gì sẽ là một ví dụ về như vậy unnecessary re-renders?
vsync

9
Khi bạn nói "Vì vậy, trong khi thuật toán diff / patch DOM ảo có lẽ không phải là giải pháp tối ưu", bạn có nghĩ đến một giải pháp tối ưu hơn về mặt lý thuyết không?
CMCDragonkai

3
Điều này dường như không trả lời câu hỏi. React yêu cầu bạn sử dụng setState để báo hiệu rằng trạng thái đã thay đổi. Nếu bạn có thể làm, this.state.cats = 99bạn vẫn sẽ cần kiểm tra bẩn để kiểm tra sự thay đổi mô hình, giống như Angular bẩn kiểm tra cây phạm vi $. Đây không phải là sự so sánh về tốc độ của hai kỹ thuật, đó đơn giản chỉ là một tuyên bố rằng React không thực hiện kiểm tra bẩn vì thay vào đó, nó có một trình thiết lập kiểu xương sống.
siêu sáng

133

Gần đây tôi đã đọc một bài viết chi tiết về thuật toán diff của React tại đây: http://calWiki.perfplanet.com/2013/diff/ . Từ những gì tôi hiểu, điều khiến React nhanh là:

  • Hoạt động đọc / ghi DOM hàng loạt.
  • Chỉ cập nhật hiệu quả của cây con.

So với kiểm tra bẩn, sự khác biệt chính của IMO là:

  1. Mô hình kiểm tra bẩn : Thành phần React được đặt rõ ràng là bẩn bất cứ khi nào setStateđược gọi, do đó không cần so sánh (về dữ liệu) ở đây. Để kiểm tra bẩn, việc so sánh (của các mô hình) luôn xảy ra mỗi vòng lặp tiêu hóa.

  2. Cập nhật DOM : Các hoạt động của DOM rất tốn kém vì sửa đổi DOM cũng sẽ áp dụng và tính toán các kiểu, bố cục CSS. Thời gian lưu từ sửa đổi DOM không cần thiết có thể dài hơn thời gian dành cho DOM ảo.

Điểm thứ hai thậm chí còn quan trọng hơn đối với các mô hình không tầm thường như một mô hình có số lượng lớn các trường hoặc danh sách lớn. Một thay đổi trường của mô hình phức tạp sẽ chỉ dẫn đến các hoạt động cần thiết cho các thành phần DOM liên quan đến trường đó, thay vì toàn bộ khung nhìn / mẫu.


1
Trên thực tế tôi cũng đã đọc một số bài viết, vì vậy bây giờ tôi (ít nhất là nói chung) cách thức hoạt động, tôi chỉ muốn tìm hiểu tại sao nó có thể hiệu quả hơn kiểm tra mô hình bẩn. Và 1) Yup, nó không so sánh các mô hình nhưng so sánh các dom ảo lớn hơn nhiều 2) Kiểm tra mô hình bẩn cung cấp cho chúng tôi khả năng cập nhật chỉ những gì cần thiết (như Angular làm)
Daniil

Tôi tin rằng chỉ có các phần của DOM ảo tương ứng với thành phần đã thay đổi phải được so sánh, trong khi kiểm tra bẩn xảy ra ở mọi vòng lặp, cho mọi giá trị trên mọi phạm vi, ngay cả khi không có gì thay đổi. Nếu lượng dữ liệu lớn thay đổi, thì Virtual DOM sẽ kém hiệu quả hơn, nhưng không thay đổi dữ liệu nhỏ.
tungd

1
Nói về Angular, bởi vì những người theo dõi cũng có thể biến đổi trạng thái trong khi tiêu hóa, việc $scope.$digestnày được thực thi nhiều lần trong mỗi chu kỳ tiêu hóa, do đó, nhiều lần so sánh dữ liệu đầy đủ so với một lần so sánh cây DOM ảo một phần.
tungd

4
thật đáng buồn khi nhiều nhà phát triển thông minh phát minh ra "hàng núi" các mánh khóe để đối phó với DOM "chậm", v.v., thay vì tập trung sự chú ý kết hợp của chúng tôi để tự sửa chữa các trình duyệt và loại bỏ DOM chậm chạp một lần. nó giống như sử dụng tất cả các nguồn lực của nhân loại để nghiên cứu các cách để đối phó với bệnh ung thư và cải thiện cuộc sống của bệnh nhân, thay vì chỉ sửa chữa ung thư. Bệnh hoạn.
vsync

@vsync DOM cần hiển thị nội dung trên màn hình. Một DOM ảo không. Ngay cả với một số DOM thực hiện lý tưởng, việc tạo một DOM ảo sẽ nhanh hơn.
Jehan

75

Tôi thực sự thích sức mạnh tiềm tàng của Virtual DOM (đặc biệt là kết xuất phía máy chủ) nhưng tôi muốn biết tất cả các ưu và nhược điểm.

- OP

React không phải là thư viện thao tác DOM duy nhất. Tôi khuyến khích bạn hiểu các lựa chọn thay thế bằng cách đọc bài viết này từ Auth0 bao gồm giải thích chi tiết và điểm chuẩn. Tôi sẽ nhấn mạnh ở đây những ưu và nhược điểm của họ, như bạn đã hỏi:

DOM ảo của React.js

nhập mô tả hình ảnh ở đây

PROS

  • Thuật toán "khuếch tán" nhanh và hiệu quả
  • Nhiều mặt trận (JSX, siêu âm)
  • Đủ nhẹ để chạy trên thiết bị di động
  • Rất nhiều lực kéo và tâm trí
  • Có thể được sử dụng mà không cần React (tức là một công cụ độc lập)

TIÊU DÙNG

  • Bản sao đầy đủ trong bộ nhớ của DOM (sử dụng bộ nhớ cao hơn)
  • Không có sự khác biệt giữa các yếu tố tĩnh và động

Cái nhìn thoáng qua của Ember.js

nhập mô tả hình ảnh ở đây

PROS

  • Thuật toán khuếch tán nhanh và hiệu quả
  • Sự khác biệt giữa các yếu tố tĩnh và động
  • Tương thích 100% với API của Ember (bạn nhận được các lợi ích mà không cần cập nhật lớn cho mã hiện tại của bạn)
  • Đại diện trong bộ nhớ nhẹ của DOM

TIÊU DÙNG

  • Chỉ được sử dụng trong Ember
  • Chỉ có một lối vào

DOM tăng dần

nhập mô tả hình ảnh ở đây

PROS

  • Giảm sử dụng bộ nhớ
  • API đơn giản
  • Dễ dàng tích hợp với nhiều giao diện và khung (có nghĩa là phụ trợ công cụ mẫu ngay từ đầu)

TIÊU DÙNG

  • Không nhanh như các thư viện khác (điều này có thể tranh cãi, xem các điểm chuẩn bên dưới)
  • Ít suy nghĩ và sử dụng cộng đồng

Việc đại diện cho thao tác DOM của ReactJS có vẻ ít đối với tôi. DOM ảo của ReactJS là DOM thay đổi hoàn toàn, không phải DOM thực tế - đúng không? Tôi đang xem bài viết gốc các tài liệu tham khảo bài viết được tham khảo và đây là những gì tôi thấy - teropa.info/images/onchange_vdom_change.svg . teropa.info/blog/2015/03/02/ Từ
smile.al.d.way 30/07/18

35

Dưới đây là một nhận xét của thành viên nhóm React Sebastian Markbåge làm sáng tỏ:

React thực hiện sự khác biệt trên đầu ra (là định dạng tuần tự hóa đã biết, thuộc tính DOM). Điều này có nghĩa là dữ liệu nguồn có thể ở bất kỳ định dạng nào. Nó có thể là cấu trúc dữ liệu bất biến và trạng thái bên trong các bao đóng.

Mô hình Angular không bảo toàn tính minh bạch tham chiếu và do đó vốn có thể thay đổi. Bạn thay đổi mô hình hiện có để theo dõi các thay đổi. Điều gì xảy ra nếu nguồn dữ liệu của bạn là dữ liệu bất biến hoặc cấu trúc dữ liệu mới mỗi lần (chẳng hạn như phản hồi JSON)?

Kiểm tra bẩn và Object.observe không hoạt động ở trạng thái phạm vi đóng.

Hai điều này rất hạn chế đối với các mẫu chức năng rõ ràng.

Ngoài ra, khi độ phức tạp mô hình của bạn tăng lên, việc theo dõi bẩn ngày càng trở nên tốn kém. Tuy nhiên, nếu bạn chỉ thực hiện khác biệt trên cây trực quan, như React, thì nó sẽ không tăng nhiều vì lượng dữ liệu bạn có thể hiển thị trên màn hình tại bất kỳ điểm nào được giới hạn bởi UI. Liên kết của Pete ở trên bao gồm nhiều lợi ích hoàn hảo hơn.

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


2
Trên thực tế về đoạn cuối: nó nên sai: mô hình lớn hơn dom ảo vì với mỗi giá trị mô hình có (trong hầu hết các trường hợp) có ít nhất một yếu tố dom ảo (và thường nhiều hơn một). Tại sao tôi muốn mô hình không được hiển thị?
Daniil

2
Bộ sưu tập lưu trữ bộ nhớ cache.
kentor

-2

Virtual Dom không được phát minh bằng phản ứng. Nó là một phần của HTML dom. Nó rất nhẹ và tách rời khỏi các chi tiết triển khai dành riêng cho trình duyệt.

Chúng tôi có thể nghĩ DOM ảo là bản sao đơn giản và cục bộ của DOM DOM. Nó cho phép React thực hiện các tính toán của nó trong thế giới trừu tượng này và bỏ qua các hoạt động DOM thực tế của DOM, thường chậm và cụ thể theo trình duyệt. Trên thực tế không có sự khác biệt lớn giữa DOM và VIRTUAL DOM.

Dưới đây là những điểm tại sao Virtual Dom được sử dụng (nguồn Virtual DOM trong ReactJS ):

Khi bạn làm:

document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
  1. Trình duyệt cần phân tích HTML
  2. Nó loại bỏ phần tử con của ElementId
  3. Cập nhật giá trị DOM với giá trị mới
  4. Tính lại css cho cha mẹ và con
  5. Cập nhật bố cục tức là từng yếu tố phối hợp chính xác trên màn hình
  6. Đi qua cây render và vẽ nó trên màn hình trình duyệt

Tính toán lại CSS và bố cục thay đổi sử dụng thuật toán phức tạp và chúng ảnh hưởng đến hiệu suất.

Cũng như cập nhật các thuộc tính DOM tức là. các giá trị. Nó tuân theo một thuật toán.

Bây giờ, giả sử nếu bạn cập nhật DOM trực tiếp 10 lần, thì tất cả các bước trên sẽ chạy từng cái một và việc cập nhật thuật toán DOM sẽ mất thời gian để cập nhật giá trị DOM.

Đây là lý do tại sao Real DOM chậm hơn DOM ảo.


3
Về ví dụ, nếu bạn đang điều chỉnh dom trực tiếp hoặc thông qua một dom ảo, thì cuối cùng cho cả hai trường hợp bạn đang thay đổi dom.
magallanes

Có trong cả hai trường hợp chúng tôi đang cập nhật dom nhưng trong trường hợp dom ảo, nó cập nhật cụ thể khóa đó (được xác định duy nhất bởi thuật toán khác với phản ứng) hoặc chỉ thẻ trường phần tử. Trong khi cập nhật cập nhật dom hoặc làm mới toàn bộ dom.
Hemant Nagarkoti

11
Tôi đã xem bài viết này từ hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130 . Có lẽ tốt hơn là chỉ ra nguồn nếu bạn không phải là tác giả.
Jinggang

2
"Đây là lý do tại sao Real DOM chậm hơn DOM ảo." Không thưa ngài, bạn chỉ sai.
Roecrew
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.