DOM и JS-фреймворки


В фреймворках React и Vue используется концепт «Virtual DOM». Это представление «реального» UI, то есть DOM-а в браузере пользователя, в виде объекта в JS. Этот объект хранится в памяти браузера и представляет собой такую же иерархическую структуру, что и настоящее DOM-дерево. Упрощённо говоря — так:

<div class="box">
<h1>Title</h1>
</div>
const virtualNode = {
type: "div",
props: {
className: "box",
children: [
{
type: "h1",
props: {
children: ["Title"],
},
},
],
},
};

Зачем делать такую копию DOM-а в памяти? Это нужно для оптимизации работы с настоящим DOM-ом в браузере. Возьмём пример: в браузере отрисовано 1000 DOM-нод, среди них нужно заменить одну ноду. Брать и заменять всё содержимое родительской ноды — неоптимально.

Лучше будет:

  1. Хранить предыдущее и новое состояние (в памяти, виртуальном DOM-е).

  2. По специальному алгоритму найти различия между двумя состояниями.

  3. И затем синхронизировать реальное и виртуальное представление DOM-а, обновив точечно только нужные части дерева.

Этот процесс «сверки» нод в React называется reconciliation (в русском уже адаптировалось «реконсиляция»). Полное сравнение двух DOM-деревьев может быть довольно «дорогим» по ресурсам, особенно когда нод в них много. Поэтому во фреймворках в алгоритмах сверки и обновления заложены допущения, позволяющие избежать трат слишком больших ресурсов компьютера.

Например:

  1. В повторяющихся наборах (списках, листингах) каждая нода помечается уникальным «ключом» — атрибутом key. По таким «подсказкам от разработчика» (уникальным идентификаторам, хэшам) фреймворку легче сравнивать ноды в DOM-деревьях: можно распознать изменение, не залезая внутрь ноды и не ориентируясь на её очерёдность в списке. Задача сводится к работе с «набором ключей» (HashMap): фреймворк определяет появление элементов с новыми ключами или изменение порядка элементов по их ключам.

  2. Если меняется тип DOM-ноды, например, с <p> на <div>, то фреймворк заменит саму ноду и все её дочерние элементы целиком.