Почему концепция React Virtual DOM считается более производительной, чем грязная проверка моделей?

372

Я видел выступление разработчика React ( Пит Хант: React: переосмысление лучших практик - JSConf EU 2013 ), и докладчик отметил, что проверка модели может быть медленной. Но не является ли вычисление различий между виртуальными DOM на самом деле еще менее производительным, поскольку виртуальная DOM в большинстве случаев должна быть больше, чем модель?

Мне действительно нравится потенциальная мощь Virtual DOM (особенно рендеринг на стороне сервера), но я хотел бы знать все плюсы и минусы.

Daniil
источник
Я думаю, что вы могли бы упомянуть и этот доклад на youtube.com/watch?v=-DX3vJiqxm4, где он специально говорит о тестах.
Инафалькао

Ответы:

493

Я основной автор модуля virtual-dom , поэтому я могу ответить на ваши вопросы. На самом деле есть 2 проблемы, которые необходимо решить здесь

  1. Когда мне сделать рендеринг? Ответ: Когда я наблюдаю, что данные грязные.
  2. Как мне эффективно сделать рендер? Ответ: Использование виртуального DOM для создания реального патча DOM

В React каждый из ваших компонентов имеет состояние. Это состояние похоже на наблюдаемое, которое вы можете найти в нокауте или других библиотеках стилей MVVM. По сути, React знает, когда нужно заново визуализировать сцену, потому что он способен наблюдать, когда эти данные изменяются. Грязная проверка выполняется медленнее, чем наблюдаемые, потому что необходимо регулярно опрашивать данные и рекурсивно проверять все значения в структуре данных. Для сравнения, установка значения для состояния будет сигнализировать слушателю, что какое-то состояние изменилось, поэтому React может просто прослушать события изменения состояния и поставить в очередь повторный рендеринг.

Виртуальный DOM используется для эффективного повторного рендеринга DOM. Это на самом деле не связано с грязной проверкой ваших данных. Вы можете выполнить рендеринг с использованием виртуального DOM с грязной проверкой или без нее. Вы правы в том, что при вычислении различий между двумя виртуальными деревьями возникают некоторые накладные расходы, но виртуальная разность DOM заключается в понимании того, что необходимо обновить в DOM, а не в том, изменились ли ваши данные. Фактически, алгоритм diff сам по себе является грязной проверкой, но он используется, чтобы увидеть, не является ли DOM грязным.

Мы стремимся перерисовывать виртуальное дерево только при изменении состояния. Таким образом, использование наблюдаемой для проверки, изменилось ли состояние, является эффективным способом предотвращения ненужных повторных визуализаций, которые могут привести к большому количеству ненужных различий дерева. Если ничего не изменилось, мы ничего не делаем.

Виртуальный DOM хорош, потому что он позволяет нам писать наш код, как будто мы перерисовываем всю сцену. За кулисами мы хотим вычислить операцию исправления, которая обновляет DOM, чтобы посмотреть, как мы ожидаем. Таким образом, хотя алгоритм DOM diff / patch виртуальных DOM, вероятно, не является оптимальным решением , он дает нам очень хороший способ выразить наши приложения. Мы просто объявляем, чего именно хотим, и React / virtual-dom решит, как сделать вашу сцену такой. Нам не нужно вручную манипулировать DOM или запутываться в предыдущем состоянии DOM. Нам также не нужно перерисовывать всю сцену, что может быть гораздо менее эффективно, чем ее исправление.

Мэтт Эш
источник
1
React выполняет грязную проверку реквизита компонентов? Я спрашиваю, потому что нет функции setProps ().
Беннлич
1
что будет примером такого unnecessary re-renders?
vsync
9
Когда вы говорите: «Хотя алгоритм DIF / patch виртуального DOM, вероятно, не является оптимальным решением», вы имеете в виду теоретически более оптимальное решение?
CMCDragonkai
3
Это не совсем похоже на ответ на вопрос. React требует, чтобы вы использовали setState, чтобы сигнализировать об изменении состояния. Если бы вы могли это сделать, this.state.cats = 99вам все равно понадобится грязная проверка для проверки изменения модели, так же как Angular dirty проверяет дерево $ scope. Это не сравнение скорости двух техник, это просто утверждение, что React не выполняет грязную проверку, потому что вместо него есть установщик стиля Backbone.
суперсветовой
133

Недавно я прочитал подробную статью об алгоритме сравнения React здесь: http://calendar.perfplanet.com/2013/diff/ . Из того, что я понимаю, что делает React быстрым:

  • Пакетные операции чтения / записи DOM.
  • Эффективное обновление только поддерева.

По сравнению с грязной проверкой ключевые отличия IMO:

  1. Грязная проверка модели : компонент React явно устанавливается как грязный при каждом setStateвызове, поэтому здесь не требуется никакого сравнения (данных). Для грязной проверки сравнение (моделей) всегда происходит в каждом цикле дайджеста.

  2. Обновление DOM : операции DOM очень дороги, потому что модификация DOM также будет применяться и вычислять стили CSS, макеты. Сэкономленное время от ненужной модификации DOM может быть больше, чем время, потраченное на распространение виртуальной DOM.

Второй пункт еще более важен для нетривиальных моделей, таких как модель с огромным количеством полей или большим списком. Одно изменение поля сложной модели приведет только к операциям, необходимым для элементов DOM, включающих это поле, вместо всего представления / шаблона.

tungd
источник
1
На самом деле я тоже читал некоторые статьи, поэтому теперь я (по крайней мере, в целом), как это работает, я просто хотел выяснить, почему это может быть более эффективным, чем грязная проверка модели. И 1) Да, он не сравнивает модели, но сравнивает гораздо большую виртуальную дом 2) Грязная проверка модели дает нам возможность обновлять только то, что нужно (как это делает Angular)
Даниил
Я считаю, что нужно сравнивать только те части виртуального DOM, которые соответствуют измененному компоненту, в то время как грязная проверка происходит каждый цикл дайджеста, для каждого значения в каждой области, даже если ничего не изменилось. Если большой объем данных изменился, то Virtual DOM был бы менее эффективен, но не для небольших изменений данных.
tungd
1
Говоря об Angular, поскольку наблюдатели также могут изменять состояние во время дайджеста, они $scope.$digestвыполняются несколько раз за цикл дайджеста, поэтому это многократное время полного сравнения данных по сравнению с одним временем частичного сравнения виртуального дерева DOM.
tungd
4
грустно, что многие умные разработчики придумывают «горы» уловок, чтобы иметь дело с «медленным» DOM и так далее, вместо того, чтобы концентрировать наше объединенное внимание на том, чтобы просто исправить сами браузеры и избавить нас от медлительности DOM раз и навсегда. это все равно, что использовать все ресурсы человечества, чтобы исследовать способы борьбы с раком и улучшить жизнь пациента, а не просто вылечить сам рак. Высмеивает.
vsync
@vsync DOM должен отображать вещи на экране. Виртуальный DOM нет. Даже при некотором идеальном выполнении DOM создание виртуального DOM будет быстрее.
Jehan
75

Мне действительно нравится потенциальная мощь Virtual DOM (особенно рендеринг на стороне сервера), но я хотел бы знать все плюсы и минусы.

- ОП

React - не единственная библиотека манипулирования DOM. Я рекомендую вам понять альтернативы, прочитав эту статью от Auth0, которая включает подробное объяснение и тесты. Я выделю здесь их плюсы и минусы, как вы спросили:

Виртуальный DOM React.js

введите описание изображения здесь

ПРОФИ

  • Быстрый и эффективный «дифференцирующий» алгоритм
  • Несколько интерфейсов (JSX, гиперскрипт)
  • Достаточно легкий, чтобы работать на мобильных устройствах
  • Много тяги и ума
  • Может использоваться без React (т.е. как независимый двигатель)

МИНУСЫ

  • Полная копия DOM в памяти (более интенсивное использование памяти)
  • Нет различия между статическими и динамическими элементами

Ember.js 'Glimmer

введите описание изображения здесь

ПРОФИ

  • Быстрый и эффективный алгоритм сравнения
  • Различие между статическими и динамическими элементами
  • 100% совместимость с API Ember (вы получаете преимущества без значительных обновлений существующего кода)
  • Облегченное представление DOM в памяти

МИНУСЫ

  • Предназначено для использования только в Ember
  • Доступен только один интерфейс

Инкрементальный DOM

введите описание изображения здесь

ПРОФИ

  • Уменьшенное использование памяти
  • Простой API
  • Легко интегрируется со многими интерфейсами и фреймворками (изначально задумывался как бэкэнд механизма шаблонов)

МИНУСЫ

  • Не так быстро, как другие библиотеки (это спорно, см тестов ниже)
  • Меньше разума и использования сообщества
falsarella
источник
Представление манипуляций с DOM в ReactJS кажется мне не слишком удачным. Виртуальный DOM ReactJS - это тот, который полностью меняется, а не фактический DOM - правильно? Я смотрю на оригинальную статью, на которую ссылаются ссылки, и вот что я вижу - teropa.info/images/onchange_vdom_change.svg . teropa.info/blog/2015/03/02/…
smile.al.d.way
35

Вот комментарий члена команды React Себастьяна Маркбога, который проливает некоторый свет:

React выполняет анализ выходных данных (это известный сериализуемый формат, атрибуты DOM). Это означает, что исходные данные могут быть любого формата. Это могут быть неизменяемые структуры данных и состояния внутри замыканий.

Модель Angular не сохраняет ссылочную прозрачность и поэтому является изменчивой по своей природе. Вы изменяете существующую модель, чтобы отслеживать изменения. Что если ваш источник данных - это неизменяемые данные или новая структура данных каждый раз (например, ответ JSON)?

Грязная проверка и Object.observe не работают с состоянием области закрытия.

Эти две вещи очень ограничивают функциональные паттерны.

Кроме того, когда сложность вашей модели возрастает, делать грязное отслеживание становится все дороже. Однако, если вы выполняете только диффузию по визуальному дереву, например, React, оно не увеличивается так сильно, поскольку объем данных, которые вы можете отобразить на экране в любой заданной точке, ограничен пользовательским интерфейсом. Приведенная выше ссылка Пита охватывает больше преимуществ.

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

Софи Альперт
источник
2
На самом деле о последнем абзаце: это должно быть неправильно: модель больше виртуального dom, потому что для каждого значения модели есть (в большинстве случаев) хотя бы один виртуальный элемент dom (и обычно гораздо больше одного). Почему я хочу модель, которая не показана?
Даниил
2
Нумерация кэшированных коллекций.
Кентор
-2

Виртуальный Дом не изобретен по реакции. Это часть HTML-домена. Он легкий и не связан с деталями реализации браузера.

Мы можем рассматривать виртуальный DOM как локальную и упрощенную копию React HTML DOM. Это позволяет React выполнять свои вычисления в этом абстрактном мире и пропускать «реальные» операции DOM, часто медленные и специфичные для браузера. На самом деле нет большой разницы между DOM и VIRTUAL DOM.

Ниже приведены пункты, по которым используется Virtual Dom (исходный Virtual 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.

Вот почему Real DOM медленнее, чем виртуальный DOM.

Хемант Нагаркоти
источник
3
Пример: если вы модифицируете dom напрямую или через виртуальный dom, то, наконец, в обоих случаях вы меняете dom.
Магалланес
Да, в обоих случаях мы обновляем dom, но в случае виртуального dom он обновляет только тот ключ (только то, что алгоритм отличается от реакции) или только тег элемента. Принимая во внимание, что обновление dom обновляет или полностью обновляет весь dom.
Хемант Нагаркоти,
11
Я видел эту статью от hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130 . Может быть, лучше указать источник, если вы не автор.
Цзинган
2
«Вот почему Real DOM медленнее, чем виртуальный DOM». Нет, сэр, вы просто не правы.
Roecrew