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

Что такое DOM


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

DOM (аббревиатура от Document Object Model) — способ представления структурного документа с помощью объектов. Это кроссплатформенное и языко-независимое соглашение для представления и взаимодействия с данными в HTML, XML и т.д.

Веб-браузеры обрабатывают составляющие DOM, и мы можем взаимодействовать с ними, используя JavaScript и CSS. Мы можем работать с узлами документа, изменять их данные, удалять и вставлять новые узлы. В наши дни DOM API является практически кроссплатформенным и кроссбраузерным.
Так в чем же проблема?

Проблема DOM


Главная проблема DOM — он никогда не был рассчитан для создания динамического пользовательского интерфейса (UI). Мы можем работать с ним, используя JavaScript и библиотеки наподобие jQuery, но их использование не решает проблем с производительностью.
Посмотрите на современные социальные сети, такие как Twitter, Facebook или Pinterest.
После небольшого скроллинга, мы будем иметь десятки тысяч DOM-узлов, эффективно взаимодействовать с которыми — задача не из легких.

Для примера, попробуйте переместить 1000 div-блоков на 5 пикселей влево.
Это может занять больше секунды — это слишком много для современного интернета. Вы можете оптимизировать скрипт и использовать некоторые приемы, но в итоге это вызовет лишь головную боль при работе с огромными страницами и динамическим UI.

Можем ли мы решить эту проблему? Похоже, что можем.
В настоящее время W3C работает над новым стандартом Shadow DOM.
Shadow DOM — это рабочий черновик стандарта W3C. Спецификация, описывающая метод объединения нескольких DOM-деревьев в одну иерархию и как эти деревья взаимодействуют друг с другом в пределах документа, что позволяет лучше скомпоновать DOM.

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

Virtual DOM


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

Такой подход работает быстрее, потому как не включает в себя все тяжеловесные части реального DOM.
Но только если мы делаем это правильно. Есть две проблемы: когда именно делать повторную перерисовку DOM и как это сделать эффективно.

Когда?
Когда данные изменяются и нуждается в обновлении.
Есть два варианта узнать, что данные изменились:
  • Первый из них — «dirty checking» (грязная проверка) заключается в том, чтобы опрашивать данные через регулярные промежутки времени и рекурсивно проверять все значения в структуре данных.
  • Второй вариант — «observable» (наблюдаемый) заключается в наблюдении за изменением состояния. Если ничего не изменилось, мы ничего не делаем. Если изменилось, мы точно знаем, что нужно обновить.

Как?
Что делает этот подход действительно быстрым:
  • Эффективные алгоритмы сравнения
  • Группировка операций чтения/записи при работе с DOM
  • Эффективное обновление только под-деревьев

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

React JS


React JS — это JavaScript-библиотека, разработанная в Facebook для создания пользовательских интерфейсов, которая популяризировала идею использования виртуального DOM. React создает легковесное дерево из JavaScript-объектов для имитации DOM-дерева. Затем он создает из них HTML, который вставляется или добавляется к нужному DOM-элементу, что вызывает перерисовку страницы в браузере.
React — это библиотека, а не фреймворк, поэтому сравнивать его с Angular или Ember некорректно.

Другие библиотеки и фреймворки


  • virtual-dom — реализация Virtual DOM от Matt Esch, алгоритм сравнения отличий.
  • Mithril — Javascript-фреймворк для создания ярких приложений.
  • Bobril — Компонент-ориентированный фреймворк, вдохновленный подходами Mithril и ReactJs.
  • cito.js — JavaScript-фреймворк для создания быстрых, масштабируемых и модульных веб-приложений.


Вывод


Virtual DOM — это техника и набор библиотек / алгоритмов, которые позволяют нам улучшить производительность на клиентской стороне, избегая прямой работы с DOM путем работы с легким JavaScript-объектом, имитирующем DOM-дерево.

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

От переводчика


Оригинальная статья: What is Virtual DOM
Примечание: при переводе допущены некоторые вольности, но в рамках разумного.

Комментарии (14)


  1. horlon
    29.04.2015 14:43
    -4

    Посмотрите на современные социальные сети, такие как Twitter, Facebook или Pinterest.
    После небольшого скроллинга, мы будем иметь десятки тысяч DOM-узлов, эффективно взаимодействовать с которыми — задача не из легких.

    Для меня это никогда не было проблемой. Это, скорее, не оптимальная разработка, навешивание лишнего, костылей. Допустим, нередко видел как для изменения содержания поля вешают целую библиотеку JQery, вместо строчки document.getElementById(«input»).value = 'value'.


    1. Fesor
      29.04.2015 14:59
      +5

      ммм… то есть вы думаете что если разработчик при реализаци фичи делает N операций с DOM то от того что он заменит одно API другим что-то сильно поменяется?

      document.getElementById(«input»).value = 'value'.
      


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

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


      1. horlon
        30.04.2015 08:31
        -2

        Не убедительно. Хотите сказать, что повесить библиотеку и дописать на ней, фактически, такое же количество кода будет быстрее самого кода на чистом JS?


        1. TimsTims
          30.04.2015 09:19

          Дело не в количестве кода, а удобстве для пользователя, у которого браузер будет меньше лагать. Главное — это пользователь


        1. stas404 Автор
          30.04.2015 09:26
          +2

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


  1. MyCTuK
    30.04.2015 09:26

    Буквально вчера писал код, который после перетаскивания объекта (jquery.ui dropping) должен перетаскиваемый объект переместить внутрь того, на который его бросаем.

    $(obj).detach();
    $(destination).append(obj);

    Всего пользователь может перетащить порядка 20 объектов сразу друг за другом. где-то после 5-го броска chrome и firefox начинают надрываться.

    Без контекста сложно понять зачем делать изменения в DOM, но задача была не портить ранее написанный код и применить для выравнивания объектов css (float:left). Лень двигатель прогресса :)


  1. tsabir
    30.04.2015 11:25
    +1

    Реальная крутизна virtual-dom чувствуется, когда ты начинаешь работать со всем документом как с целым значением. Т.е. не ищешь элемент который надо поменять, а тупо генеришь заново весь виртуальный документ целиком. Это очень удобно, так как логика поведения приложения превращается в последовательность состояний документа (с точки зрения кода). А как точечно применить изменения за тебя думает virtual-dom. Конечно, все это не без ньюансов, но в целом идея очень многим нравится.


  1. xargon
    30.04.2015 13:44
    +2

    Ну так и что, есть пример перемещения 1.000 div-ов, с использованием Virtual DOM?


  1. ShpuntiK
    01.05.2015 10:36

    Понимаю, что перевод, но:

    Посмотрите на современные социальные сети, такие как Twitter, Facebook или Pinterest.
    После небольшого скроллинга, мы будем иметь десятки тысяч DOM-узлов, эффективно взаимодействовать с которыми — задача не из легких.

    В Pinterest никаких тысяч, а тем более десятков тысяч элентов не будет. Там всегда около 100-150 элементов и при скроллинге одни удаляются и вставляются новые или просто содержимое заменяется.


    1. Fesor
      01.05.2015 10:47

      Если не удалять/заменять то как раз таки тысячи и будут. Суть именно в оптимизациях.


    1. stas404 Автор
      01.05.2015 12:41

      Так ведь, как раз «React is a JavaScript library for creating user interfaces by Facebook and Instagram.»
      facebook.github.io/react/docs/why-react.html


      1. stas404 Автор
        01.05.2015 13:04

        По поводу конкретно Pinterest — есть такое упоминание:

        React is a Facebook project and is what fuels FB’s comment system and most of FB’s projects. It’s also largely used on Pinterest, AirBnB, Khan Academy and a plethora of other startups. Atom, the “hackable editor”, is now built on it and I heard Microsoft is also supporting the project.
        Все они используют подобный подход, иначе бы было именно так, как написал автор.


  1. stas404 Автор
    25.05.2015 15:46

    Наткнулся на ссылку «Virtual DOM Benchmark».
    Возможно, будет интересно: vdom-benchmark.github.io/vdom-benchmark
    Рассмотреные реализации:

    • uix
    • cito.js
    • Bobril
    • React
    • virtual-dom
    • mithril
    • maquette
    • dom-layer


    1. nuit
      26.05.2015 12:07

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