В этой статье мы собираемся обсудить React Virtual DOM и то, как Reconciliation работает под капотом.

Введение

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

Вот шаги, которые браузер выполняет для отображения нашего веб-сайта:

  1. Анализ HTML :
    Браузер анализирует наш HTML и сохраняет его в памяти в виде древовидной структуры документа, который также известен как DOM (объектная модель документа) или иногда как Real DOM. Это веб-API, используемый для создания веб-сайтов.
    Методы DOM обеспечивают программный доступ к дереву. С их помощью вы можете изменить структуру, стиль или содержание документа.
  2. Анализ CSS:
    Браузер анализирует наш CSS и сохраняет его в памяти как CSSOM (объектная модель CSS). Это веб-API для управления CSS нашего веб-сайта.
  3. Создание дерева визуализации.
    Браузер использует DOM и CSSOM для создания дерева визуализации. Дерево рендеринга представляет все, что будет отображаться в браузере (узлы HTML с их стилями).
  4. Дерево рендеринга макета:
    Браузер вычисляет геометрию всех элементов (размеры и расположение) и соответственно начинает их размещение.
  5. Рисование:
    теперь он начнет рисовать все отдельные узлы в соответствии с их стилями.

Виртуальный дом

Это представление DOM как объекта JavaScript. Это концепция, реализованная JS Libraries & Frameworks для достижения разработки пользовательского интерфейса на основе состояния. Это помогает React пакетировать изменения состояния и заботиться о плавных переходах между состояниями.

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

Я сделал 2 простых проекта часов (1 с использованием Vanilla JS и 1 с использованием React), чтобы объяснить этот момент.

Исходный код часов Vanilla JS: https://github.com/Naman-Saxena1/clock-example-vanilla-js

Исходный код React Clock: https://github.com/Naman-Saxena1/clock-example-react

Необходимость виртуального DOM

Когда мы вносим какие-либо изменения состояния в наше приложение React, оно создает новую версию всего виртуального DOM с последними обновлениями. Затем React находит элементы, которые необходимо изменить, сравнивая старое дерево Virtual DOM и обновленное дерево Virtual DOM. И затем только обновляет элементы в DOM браузера, которые изменились. React использует алгоритм сравнения для сравнения двух деревьев Virtual DOM, мы обсудим это в следующих разделах.

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

Преимущество использования 2 виртуальных деревьев DOM заключается в том, что 1 дерево действует как черновик и позже используется для пакетного обновления реального DOM. Старое дерево Virtual DOM называется Текущее дерево, а другое называется Дерево незавершенных работ (поскольку оно в основном используется как черновик). В Видео Дэна Абрамова на Youtube он объяснил, что причиной создания двух виртуальных деревьев DOM стала техника двойной буферизации, которая раньше использовалась для разработки игр.

Поэтому React сначала вносит изменения в Дерево незавершенных работ, а затем также обновляет изменения в Real DOM. Таким образом, он выполняет дополнительную работу, чем веб-сайт, написанный с использованием Vanilla JS. Но все же достаточно хорош с точки зрения производительности.

Подробнее об этом можно прочитать:





Мы используем React, а не Vanilla JS, потому что он декларативен, предлагает повторно используемые компоненты и помогает легко создавать сложный пользовательский интерфейс, абстрагируя сложные части.
Кроме того, поскольку современные веб-сайты, такие как Facebook, Netflix, Dropbox, и т. д. очень динамичны, полезно использовать дерево незавершенных работ, а затем группировать обновления.

Вот почему вы могли заметить, что если вы когда-либо делали что-то вроде приведенного ниже примера, setState() группирует обновления, поскольку он асинхронный.

Подробнее об этом можно прочитать:
https://github.com/facebook/react/issues/11527#issuecomment-360199710

Некоторые важные термины

Чтобы лучше понять, нам нужно обсудить некоторые термины, прежде чем обсуждать весь процесс примирения.

Сверка — это процесс синхронизации двух деревьев DOM с помощью такой библиотеки, как ReactDOM. Это делается с помощью Reconciler и Renderer.

Reconciler использует алгоритм сравнения для поиска различий между текущим деревом и деревом незавершенных работ и отправляет вычисленные изменения средству визуализации.

Визуализатор обновляет пользовательский интерфейс приложения. Разные устройства могут иметь разные визуализаторы при совместном использовании одного и того же согласователя.

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

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

React Fiber должен быть асинхронным, используя преимущества совместного планирования, и должен уметь делать следующее:
1. Приостанавливать работу и возвращаться к ней позже
2. Назначать приоритет различным типы работы
3. Повторное использование ранее выполненной работы
4. Прерывание работы, если она больше не нужна

fiber — это объект Javascript, представляющий единицу работы. Для каждого компонента и элемента React React создает свой собственный объект волокна. Он имеет отношение один к одному с экземпляром и управляет работой для экземпляра. А также отслеживает его отношения с другими объектами волокна в дереве Virtual DOM.

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

Priority List :
0 : No Work //No work is pending
1 : SynchronousPriority //For controlled text inputs. Synchronous side effects
2 : TaskPriority //Needs to complete at the end of the current tick
3 : AnimationPriority //Needs to complete before the next frame
4 : HighPriority //Interaction that needs to complete pretty soon to feel responsive
5 : LowPriority //Data fetching, or result from updating stores
6 : OffscreenPriority //Won't be visible but do the work in case it becomes visible

Процесс согласования

Основной поток браузера используется для создания дерева незавершенных работ с помощью React, обработки пользовательских событий, перерисовки и т. д.

Посмотрим, как все это сочетается:

  1. Когда мы вносим изменения в наше состояние, React ждет, пока основной поток станет бездействующим, а затем начинает строить на нем дерево незавершенных работ (WIP).
  2. Дерево WIP построено с использованием волокна, и структура дерева соответствует структуре компонентов в нашем коде.
  3. Этот этап (этап рендеринга/согласования) построения дерева WIP и определения необходимых изменений является асинхронным и может быть приостановлен, если основной поток должен выполнить какую-либо другую работу. В этом случае основной поток начинает работать над этими обновлениями в соответствии с их приоритетом в списке приоритетов. Как только основной поток снова простаивает, он возобновляет построение дерева WIP с того места, где он остановился в последний раз.
  4. Второй этап (этап фиксации) начинается после завершения всего дерева WIP, этот этап является синхронным и не может быть прерван. На этом этапе React внесет эти изменения в DOM. Он делает это, меняя местами указатели текущего дерева и дерева незавершенных работ. А затем сбрасывает (рендерит) эти волокна в DOM.
  5. После замены новое дерево незавершенных работ можно использовать для любых новых будущих изменений состояния.

Теперь, когда мы получили общее представление о том, как работает весь Процесс примирения, мы можем обсудить некоторые важные моменты.

  1. Во время сравнения Текущего Дерева и Дерева Текущего выполнения React отмечает волокна, которые необходимо изменить. А затем создайте из них Список эффектов, который впоследствии будет использоваться для внесения изменений в DOM.
  2. Каждое волокно имеет альтернативное свойство, указывающее на волокно в другом дереве. При создании Work in Progress Tree Reacts находит файберы, которые не нуждаются в изменениях, и просто клонирует их из Current Tree. Это помогает React повторно использовать работу.
  3. Алгоритм сравнения используется для двух вышеуказанных шагов и делает React максимально эффективным.
  4. Современные алгоритмы имеют сложность порядка O(n3), где n — количество элементов в дереве. Следовательно, React реализует эвристический алгоритм O(n), основанный на двух допущениях:
    1. Два элемента разных типов будут создавать разные деревья. Он не пытается различать их, а просто заменяет старое дерево.
    2. Разработчик может подсказать, какие дочерние элементы могут быть стабильными в разных рендерах с помощью key prop.
  5. Использование React Fiber:
    1. Границы ошибок
    2. Фрагменты
    3. Порталы

Если вы тот, кто хочет изучить React и ищет бесплатные хорошие ресурсы, я нашел Codevolution Youtube React Playlist чрезвычайно полезным.

Ниже приведены ресурсы, которые я считаю полезными для понимания React Fiber:
1. Лин Кларк React Conf 2017: https://www.youtube.com/watch?v=ZCuYPiUIONs

2. Эндрю Кларк Github: https://github.com/acdlite/react-fiber-architecture

3. Плейлист Филиппа Фабианека на YouTube: https://www.youtube.com/playlist?list=PLxRVWC-K96b0ktvhd16l3xA6gncuGP7gJ

4. Freecodecamp React Components & React Elements от Samer Buna: https://www.freecodecamp.org/news/react-interview-question-what-gets-rendered-in-the-browser-a-component-or-an -элемент-1b3eac777c85/»

Привет, ребята!
Я надеюсь, что вы нашли что-то из этого информативным или полезным. Если у вас есть какие-либо предложения / критика статьи, любезно прокомментируйте ниже.

Спасибо за прочтение!