Если вы попали сюда, значит, у вас есть идея, что React использует Virtual DOM для повышения производительности, и вы хотите лучше понять это. В этой статье мы попытаемся выяснить, что такое DOM и его проблемы, что такое Virtual DOM, как он решает проблемы DOM и как React использует Virtual DOM.

Что такое DOM?

«Объектная модель документа (DOM) W3C - это не зависящий от платформы и языка интерфейс, который позволяет программам и сценариям динамически получать доступ и обновлять содержимое, структуру и стиль документа».

DOM - это абстракция HTML-структуры страницы. Он берет элементы HTML и помещает их в объект с древовидной структурой, поддерживая отношения родительский / дочерний для этих вложенных элементов HTML. Это предоставляет API, который позволяет нам перемещаться по узлам (элементам HTML) и манипулировать ими различными способами, такими как добавление узлов, удаление узлов, редактирование содержимого узла и т. Д.

Неэффективность DOM

Изначально модель DOM предназначалась для статических интерфейсов пользователя - страниц, отображаемых сервером, не требующих динамических обновлений. Когда DOM обновляется, он должен обновить узел, а также перерисовать страницу соответствующим CSS и макетом. Скажем, у нас есть массив.

let fruit = [«Яблоко», «Апельсин», «Банан»]

Здесь мы хотим обновить апельсин до лимона. Затем нам нужно создать новый массив.

let fruit = [«Яблоко», «Лимон», «Банан»]

Эффективно мы можем просто перейти к фруктам [2] и обновить только этот элемент.

Сейчас обычным явлением является наличие тысячи узлов в одном SPA. Так что перекрашивать всю страницу при каждом изменении очень-очень дорого.

В идеале мы хотели бы повторно отображать только те элементы, которые получают обновления, оставив остальные элементы как есть.

Зная, когда обновлять

Компоненты могут определить, когда происходит обновление данных и нужно ли его повторно отображать в пользовательском интерфейсе, несколькими способами:

  • Грязная проверка (медленная). Проверяет данные всех узлов через регулярные интервалы, чтобы узнать, не произошли ли какие-либо изменения. Это неэффективно, поскольку требует рекурсивного обхода каждого узла, чтобы убедиться, что данные не «грязные» (устаревшие). Это использовалось в AngularJS 1.x.
  • Наблюдаемый (быстрый). Компоненты отвечают за прослушивание, когда происходит обновление. Поскольку данные сохраняются в состоянии, компоненты могут просто прослушивать события в состоянии и, если есть обновление, они могут повторно отобразить в пользовательском интерфейсе. React использует это.

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

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

Согласование - это процесс сравнения и синхронизации двух файлов (реального и виртуального DOM). Алгоритм дифференцирования - это метод согласования, который используется React.

Теневая модель DOM - это то же самое, что и виртуальная модель DOM?

Нет, они разные. Shadow DOM - это браузерная технология, разработанная в первую очередь для определения переменных и CSS в веб-компонентах. Виртуальная модель DOM - это концепция, реализованная библиотеками в JavaScript поверх API-интерфейсов браузера.

Как работают обновления в React?

  • При первой загрузке ReactDOM.render () создаст виртуальное дерево DOM и реальное дерево DOM.
  • Поскольку React работает с наблюдаемыми шаблонами, когда происходит какое-либо событие (например, нажатие клавиши, щелчок левой кнопкой мыши, ответ API и т. Д.), Узлы виртуального дерева DOM уведомляются об изменении свойств. Если свойства, используемые в этом узле, обновляются, узел обновляется. остальное оставил как есть.
  • React сравнивает виртуальный DOM с реальным DOM и обновляет реальный DOM. Этот процесс называется примирением. React использует методы согласования алгоритмов Diffing.
  • Обновленный реальный DOM перерисовывается в браузере.

Дополнительные моменты относительно обновлений.

  • Виртуальный DOM - это чистый JS-файл и легкий вес, поэтому запись любого обновления в Virtual DOM происходит намного быстрее, чем прямое обновление в Real DOM.
  • Реагирование занимает несколько миллисекунд до согласования. Это позволяет реагировать на объединение нескольких процессов. Это увеличивает эффективность и позволяет избежать ненужной обработки. Из-за этой задержки мы не должны полагаться на this.state.val сразу после setState ().
  • React делает поверхностное сравнение значения props. Нам нужно обрабатывать глубокое сравнение отдельно, неизменяемость - наиболее распространенный способ справиться с этим.

Примирение

React сравнивает виртуальную модель DOM с реальной моделью DOM. Он обнаруживает измененные узлы и обновляет только измененные узлы в Real DOM, оставляя остальные узлы как есть. Этот процесс называется примирением.

Общие методы согласования имеют сложность O (n3). Обычно у нас есть тысячи узлов в любом приложении. Использование общих методов обойдется слишком дорого.

React реализует эвристический алгоритм O (n), основанный на двух предположениях:

  1. Два элемента разных типов будут давать разные деревья.
  2. Разработчик может намекнуть, какие дочерние элементы могут быть стабильными при разных рендерингах с помощью ключевого свойства.

На практике эти предположения верны почти для всех практических случаев использования.

Алгоритм различения

Сначала React сравнивает два корневых элемента. Поведение различается в зависимости от типов корневых элементов.

React сравнил типы корневых элементов DOM.

  • Элементы разных типов: всякий раз, когда корневые элементы имеют разные типы, React срывает старое дерево и строит новое дерево с нуля. Переход от ‹a› к ‹img›, или от ‹Article› к ‹Comment›, или от ‹Button› к ‹div› - любой из них приведет к полному восстановлению. Это также приведет к отключению компонентов и вызовам жизненного цикла монтирования.
  • Элементы DOM одного типа: при сравнении двух элементов DOM React одного типа React просматривает атрибуты обоих, сохраняет один и тот же базовый узел DOM и обновляет только измененные атрибуты. Узел DOM, затем React выполняет рекурсию для дочерних узлов. Это приведет к вызовам жизненного цикла обновления компонентов.

Почему ключ следует использовать в списках?

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

Старый

<ul>

‹Li› первый ‹/li›

‹Li› секунда ‹/li›

</ul>

Новое

<ul>

‹Li› первый ‹/li›

‹Li› секунда ‹/li›

‹Li› третий ‹/li›

</ul>

Здесь React добавит третий элемент напрямую. Но если порядок меняется, то реагирование запутывается при сравнении. Для преодоления этого ключа введен.

<ul>

‹Li key =” 2015 ›Duke ‹/li›

‹Li key =” 2016 ›Вилланова ‹/li›

</ul>

Обновленный список.

<ul>

‹Li key =» 2014 г. ›Коннектикут ‹/li›

‹Li key =” 2015 ›Duke ‹/li›

‹Li key =” 2016 ›Вилланова ‹/li›

</ul>

Здесь react будет идентифицировать компонент с ключом и обновит только измененные элементы.

Ключи должны быть стабильными, предсказуемыми и уникальными. Нестабильные ключи (например, созданные с помощью Math.random ()) вызовут ненужное воссоздание многих экземпляров компонентов и узлов DOM, что может вызвать снижение производительности и потерю состояния дочерних компонентов.

Мы не рекомендуем использовать индексы для ключей, если порядок элементов может измениться. Это может отрицательно сказаться на производительности и вызвать проблемы с состоянием компонентов.