Dlaczego mówi się, że koncepcja wirtualnego DOM Reacta jest bardziej wydajna niż sprawdzanie brudnych modeli?

372

Widziałem przemówienie dewelopera React na ( Pete Hunt: React: Rethinking najlepsze praktyki - JSConf EU 2013 ) i mówca wspomniał, że brudne sprawdzanie modelu może być powolne. Ale czy obliczanie różnicy między wirtualnymi DOMami nie jest nawet mniej wydajne, ponieważ wirtualna DOM, w większości przypadków, powinna być większa niż model?

Bardzo podoba mi się potencjalna moc wirtualnego DOM (szczególnie renderowanie po stronie serwera), ale chciałbym poznać wszystkie zalety i wady.

Daniil
źródło
Myślę, że mógłbyś wspomnieć o tej rozmowie również youtube.com/watch?v=-DX3vJiqxm4, gdzie konkretnie mówi o testach porównawczych.
inafalcao

Odpowiedzi:

493

Jestem głównym autorem modułu wirtualnego domu , więc mogę być w stanie odpowiedzieć na twoje pytania. W rzeczywistości są tutaj 2 problemy, które należy rozwiązać

  1. Kiedy ponownie renderuję? Odpowiedź: Kiedy zauważę, że dane są brudne.
  2. Jak wydajnie renderować ponownie? Odpowiedź: Używanie wirtualnego DOM do wygenerowania prawdziwej poprawki DOM

W React każdy ze składników ma stan. Ten stan jest podobny do obserwowanego w nokautach lub innych bibliotekach typu MVVM. Zasadniczo React wie, kiedy ponownie renderować scenę, ponieważ jest w stanie obserwować zmiany tych danych. Brudne sprawdzanie jest wolniejsze niż obserwowalne, ponieważ należy odpytywać dane w regularnych odstępach czasu i sprawdzać rekurencyjnie wszystkie wartości w strukturze danych. Dla porównania ustawienie wartości w stanie zasygnalizuje słuchaczowi, że jakiś stan się zmienił, więc React może po prostu nasłuchiwać zmian w stanie i kolejkować ponowne renderowanie.

Wirtualny DOM służy do wydajnego renderowania DOM. To nie jest tak naprawdę związane z brudnym sprawdzaniem danych. Możesz ponownie renderować za pomocą wirtualnego DOM z brudnym sprawdzaniem lub bez. Masz rację, że obliczenie różnicy między dwoma wirtualnymi drzewami jest pewne, ale wirtualny DOM DOM polega na zrozumieniu, co wymaga aktualizacji w DOM, a nie na tym, czy Twoje dane uległy zmianie. W rzeczywistości algorytm porównywania sam w sobie jest brudnym narzędziem sprawdzającym, ale służy do sprawdzania, czy DOM jest zamiast tego brudny.

Naszym celem jest ponowne renderowanie drzewa wirtualnego tylko w przypadku zmiany stanu. Zatem użycie obserwowalnego do sprawdzenia, czy stan się zmienił, jest skutecznym sposobem zapobiegania niepotrzebnym ponownym renderowaniu, które powodowałoby wiele niepotrzebnych różnic w drzewach. Jeśli nic się nie zmieniło, nic nie robimy.

Wirtualny DOM jest fajny, ponieważ pozwala nam pisać nasz kod tak, jakbyśmy renderowali całą scenę. Za kulisami chcemy obliczyć operację poprawki, która aktualizuje DOM, aby wyglądał tak, jak oczekujemy. Tak więc, chociaż algorytm wirtualnego porównania / różnicowania DOM DOM nie jest prawdopodobnie optymalnym rozwiązaniem , daje nam to bardzo dobry sposób na wyrażenie naszych aplikacji. Po prostu deklarujemy dokładnie to, czego chcemy, a React / virtual-dom wypracuje sposób, aby Twoja scena wyglądała tak. Nie musimy wykonywać ręcznej manipulacji DOM ani mylić się co do poprzedniego stanu DOM. Nie musimy też ponownie renderować całej sceny, co może być znacznie mniej wydajne niż łatanie.

Matt Esch
źródło
1
Czy React wykonuje brudne sprawdzanie rekwizytów komponentów? Pytam, ponieważ nie ma funkcji setProps ().
bennlich
1
jaki byłby tego przykład unnecessary re-renders?
vsync
9
Kiedy mówisz „Więc chociaż wirtualny algorytm DOM diff / patch prawdopodobnie nie jest optymalnym rozwiązaniem”, masz na myśli teoretycznie bardziej optymalne rozwiązanie?
CMCDragonkai
3
To nie do końca odpowiada na pytanie. React wymaga użycia setState do zasygnalizowania zmiany stanu. Jeśli byłbyś w stanie to zrobić this.state.cats = 99, nadal potrzebowałbyś brudnego sprawdzania, aby sprawdzić zmianę modelu, tak jak Angular brudny sprawdza drzewo $ scope. To nie jest porównanie szybkości dwóch technik, to po prostu stwierdzenie, że React nie wykonuje brudnego sprawdzania, ponieważ zamiast tego ma seter stylu szkieletowego.
superluminarny
133

Niedawno przeczytałem szczegółowy artykuł o algorytmie różnicowym React tutaj: http://calendar.perfplanet.com/2013/diff/ . Z tego co rozumiem, co sprawia, że ​​React fast jest:

  • Partie operacji odczytu / zapisu DOM.
  • Skuteczna aktualizacja tylko sub-drzewa.

W porównaniu do „brudnej kontroli” najważniejsze różnice IMO to:

  1. Sprawdzanie brudności modelu : składnik React jest jawnie ustawiany jako brudny przy każdym setStatewywołaniu, więc nie ma potrzeby porównywania (danych) tutaj. W celu sprawdzenia, porównanie (modeli) zawsze odbywa się w każdej pętli podsumowania.

  2. Aktualizacja DOM : operacje DOM są bardzo kosztowne, ponieważ modyfikacja DOM będzie również stosować i obliczać style CSS, układy. Zaoszczędzony czas na niepotrzebnej modyfikacji DOM może być dłuższy niż czas poświęcony na różnicowanie wirtualnej DOM.

Drugi punkt jest jeszcze ważniejszy w przypadku nietrywialnych modeli, takich jak taki z dużą ilością pól lub dużą listą. Jedna zmiana złożonego modelu spowoduje tylko operacje potrzebne dla elementów DOM obejmujących to pole, zamiast całego widoku / szablonu.

wolfram
źródło
1
Właściwie przeczytałem też kilka artykułów, więc teraz (przynajmniej ogólnie), jak to działa, chciałem tylko dowiedzieć się, dlaczego może być bardziej wydajny niż brudne sprawdzanie modelu. I 1) Tak, nie porównuje modeli, ale porównuje znacznie większą wirtualną domenę 2) Brudne sprawdzenie modelu zapewnia nam możliwość aktualizacji tylko tego, co jest potrzebne (tak jak robi to Angular)
Daniil
Uważam, że należy porównywać tylko części wirtualnego DOM odpowiadające zmienionemu komponentowi, podczas gdy sprawdzanie brudu odbywa się w każdej pętli podsumowania, dla każdej wartości w każdym zakresie, nawet jeśli nic się nie zmieniło. Jeśli zmieni się duża ilość danych, wówczas wirtualny DOM będzie mniej wydajny, ale nie w przypadku niewielkiej zmiany danych.
tungd
1
Mówiąc o Angular, ponieważ obserwatorzy mogą również mutować stan podczas podsumowania, $scope.$digestjest on wykonywany wiele razy na cykl podsumowania, więc jest to wielokrotność pełnego porównania danych w porównaniu z pojedynczym czasem częściowego porównania wirtualnego drzewa DOM.
tungd
4
to smutne, że wielu inteligentnych programistów wymyśla „góry” sztuczek, aby poradzić sobie z „powolnym” DOM i tak dalej, zamiast skupiać naszą wspólną uwagę na naprawie samych przeglądarek i raz na zawsze pozbyć się spowolnienia DOM. to jak wykorzystanie całej ludzkości do badania sposobów radzenia sobie z rakiem i poprawy życia pacjenta, zamiast po prostu naprawić sam rak. Wyśmiewać
vsync
@vsync DOM musi wyświetlać rzeczy na ekranie. Wirtualny DOM nie. Nawet przy niektórych DOM o idealnej wydajności tworzenie wirtualnego DOM będzie szybsze.
Jehan
75

Bardzo podoba mi się potencjalna moc wirtualnego DOM (szczególnie renderowanie po stronie serwera), ale chciałbym poznać wszystkie zalety i wady.

- OP

React nie jest jedyną biblioteką manipulacji DOM. Zachęcam do zrozumienia alternatyw, czytając ten artykuł z Auth0, który zawiera szczegółowe wyjaśnienia i testy porównawcze. Podkreślę tutaj ich zalety i wady, jak zapytałeś:

Wirtualny DOM React.js

wprowadź opis zdjęcia tutaj

PROS

  • Szybki i wydajny algorytm „różnicowania”
  • Wiele nakładek (JSX, hyperscript)
  • Wystarczająco lekki, aby działać na urządzeniach mobilnych
  • Dużo trakcji i dzielenia umysłu
  • Może być używany bez React (tj. Jako niezależny silnik)

CONS

  • Pełna kopia DOM w pamięci (większe użycie pamięci)
  • Brak rozróżnienia między elementami statycznymi i dynamicznymi

Ember.js 'Glimmer

wprowadź opis zdjęcia tutaj

PROS

  • Szybki i wydajny algorytm różnicowania
  • Rozróżnienie między elementami statycznymi i dynamicznymi
  • W 100% kompatybilny z API Embera (zyskujesz bez większych aktualizacji istniejącego kodu)
  • Lekka reprezentacja DOM w pamięci

CONS

  • Przeznaczony do użycia tylko w Ember
  • Dostępny tylko jeden interfejs

Przyrostowy DOM

wprowadź opis zdjęcia tutaj

PROS

  • Zmniejszone zużycie pamięci
  • Proste API
  • Łatwo integruje się z wieloma frontendami i frameworkami (od samego początku jako backend silnika szablonów)

CONS

  • Nie tak szybko, jak inne biblioteki (jest to dyskusyjne, patrz testy porównawcze poniżej)
  • Mniejszy udział umysłowy i korzystanie ze społeczności
falsarella
źródło
Reprezentacja manipulacji DOM przez ReactJS nie wydaje mi się zbyt duża. Wirtualny DOM ReactJS to ten, który zmienia się całkowicie, a nie rzeczywisty DOM - prawda? Patrzę na oryginalny artykuł, do którego się odwołują, i oto, co widzę - teropa.info/images/onchange_vdom_change.svg . teropa.info/blog/2015/03/02/…
smile.al.d.way
35

Oto komentarz członka zespołu React, Sebastiana Markbåge, który rzuca nieco światła:

React robi różnicowanie na wyjściu (który jest znanym formatem szeregowalnym, atrybuty DOM). Oznacza to, że dane źródłowe mogą mieć dowolny format. Mogą to być niezmienne struktury danych i stan wewnątrz zamknięć.

Model kątowy nie zachowuje przejrzystości odniesienia i dlatego jest z natury zmienny. Mutujesz istniejący model, aby śledzić zmiany. Co się stanie, jeśli źródłem danych są niezmienne dane lub nowa struktura danych za każdym razem (np. Odpowiedź JSON)?

Brudne sprawdzanie i Object.observe nie działa w stanie zakresu zamknięcia.

Te dwie rzeczy ograniczają się oczywiście do wzorów funkcjonalnych.

Ponadto, gdy złożoność modelu rośnie, wykonywanie brudnego śledzenia staje się coraz droższe. Jeśli jednak różnicujesz tylko w drzewie wizualnym, takim jak React, nie wzrośnie ono tak bardzo, ponieważ ilość danych, które możesz wyświetlić na ekranie w dowolnym punkcie, jest ograniczona przez interfejsy użytkownika. Powyższy link Pete'a obejmuje więcej korzyści.

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

Sophie Alpert
źródło
2
Właściwie o ostatnim akapicie: powinno być źle: model jest większy niż domena wirtualna, ponieważ dla każdej wartości modelu istnieje (w większości przypadków) co najmniej jeden element domeny wirtualnej (i zwykle znacznie więcej niż jeden). Dlaczego chcę model, który nie jest pokazany?
Daniil
2
Paginacja kolekcji w pamięci podręcznej.
kentor
-2

Dom wirtualny nie został wymyślony przez zareaguj. Jest to część domeny HTML. Jest lekki i oderwany od szczegółów implementacji specyficznych dla przeglądarki.

Możemy myśleć o wirtualnym DOM jako lokalnej i uproszczonej kopii HTML DOM. Pozwala Reactowi wykonywać obliczenia w tym abstrakcyjnym świecie i pomijać „prawdziwe” operacje DOM, często wolne i specyficzne dla przeglądarki. W rzeczywistości nie ma dużej różnicy między DOM a DOMEM WIRTUALNYM.

Poniżej znajdują się informacje na temat korzystania z Virtual Dom (źródłowy Virtual DOM w ReactJS ):

Kiedy to zrobisz:

document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
  1. Przeglądarka musi przeanalizować kod HTML
  2. Usuwa element podrzędny elementId
  3. Aktualizuje wartość DOM o nową wartość
  4. Ponownie oblicz css dla rodzica i dziecka
  5. Zaktualizuj układ, tj. Dokładnie na każdym elemencie współrzędne na ekranie
  6. Przejdź przez drzewo renderowania i pomaluj je na ekranie przeglądarki

Ponowne obliczenie CSS i zmienionych układów używa złożonego algorytmu i wpływa na wydajność.

Oprócz aktualizacji właściwości DOM tj. wartości. Postępuje zgodnie z algorytmem.

Załóżmy teraz, że jeśli zaktualizujesz DOM 10 razy bezpośrednio, wówczas wszystkie powyższe kroki będą uruchamiane jeden po drugim, a aktualizacja algorytmów DOM zajmie trochę czasu, aby zaktualizować wartości DOM.

To dlatego Real DOM jest wolniejszy niż wirtualny DOM.

Hemant Nagarkoti
źródło
3
O przykładzie, jeśli modyfikujesz dom bezpośrednio lub za pośrednictwem wirtualnego domu, to w końcu w obu przypadkach zmieniasz dom.
magallanes
Tak, w obu przypadkach aktualizujemy dom, ale w przypadku domeny wirtualnej aktualizuje ten konkretny tylko klucz (unikalnie zdefiniowany przez algorytm różni się od reagowania) tylko pole lub znacznik elementu. Podczas gdy aktualizacja domeny aktualizuje lub całkowicie odświeża całą domenę.
Hemant Nagarkoti
11
Widziałem ten artykuł z hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130 . Może lepiej wskazać źródło, jeśli nie jesteś autorem.
Jinggang,
2
„Właśnie dlatego Real DOM jest wolniejszy niż wirtualny DOM”. Nie, proszę pana, po prostu się mylisz.
Roecrew