Що таке Virtual DOM?

11 хв. читання

Пригадаємо що таке DOM. Document Object Model (або Об'єктна Модель Документу) — об'єктне представлення вмісту HTML-документу та інтерфейс для управління цим об'єктом. Shadow DOM можна розглядати як «полегшену» версію DOM. HTML-елементи також представлені у вигляді об'єктів, проте тут ми не маємо справу з окремим документом. Shadow DOM дозволяє розділити наш DOM на невеликі інкапсульовані частини, що можуть використовуватись в HTML-документі.

Напевно ви зустрічали ще один схожий термін — Virtual DOM. Ця концепція існує вже декілька років, й здобула популярність завдяки React.

У статті дізнаємось, що таке Virtual DOM, чим він відрізняється від звичайного DOM, та як використовується.

Навіщо нам Virtual DOM?

Щоб зрозуміти, чому виникла концепція віртуального DOM, повернемося до звичайного DOM. Як було зазначено, DOM складається з двох частин — об'єктне представлення HTML-документа та API для керування цим об'єктом.

Наприклад, розглянемо простий HTML-документ з невпорядкованим списком з одного елементу.

<!doctype html>
<html lang="en">
 <head></head>
 <body>
    <ul class="list">
        <li class="list__item">List item</li>
    </ul>
  </body>
</html>

Документ можна представити деревом DOM:

Що таке Virtual DOM?

Припустимо, ми хочемо змінити вміст першого елемента списку на List item one, а також додати другий елемент. Нам необхідно звернутися до DOM API, щоб знайти елементи, які ми хочемо змінити, створити нові елементи і додати атрибути та вміст. Нарешті, ми можемо оновити самі DOM-елементи.

const listItemOne = document.getElementsByClassName("list__item")[0];
listItemOne.textContent = "List item one";

const list = document.getElementsByClassName("list")[0];
const listItemTwo = document.createElement("li");
listItemTwo.classList.add("list__item");
listItemTwo.textContent = "List item two";
list.appendChild(listItemTwo);

DOM не був створений для цього...

Коли в 1998 році була випущена перша специфікація DOM, створення та управління веб-сторінками виглядало інакше. Ми набагато менше покладались на DOM API для створення та оновлення вмісту сторінок.

Прості методи, на зразок document.getElementsByClassName(), нe розв'язують масштабних проблeм. Якщо ми кожні декілька секунд оновлюємо декілька елементів на сторінці, згаданий метод виявиться дуже неефективним через постійні запити та оновлення DOM.

Крім того, зважаючи на спосіб налаштування API, нам легше виконувати більш «дорогі» операції (коли ми оновлюємо великі частини документу, а не конкретні елементи).

Повернемось до нашого прикладу зі списком. Нам дещо легше замінити увесь список на новий, ніж змінювати певні елементи.

const list = document.getElementsByClassName("list")[0];
list.innerHTML = `
<li class="list__item">List item one</li>
<li class="list__item">List item two</li>
`;

У прикладі ми не відчуємо помітної різниці у продуктивності. Проте зі збільшенням веб-сторінки, ми відчуваємо потребу оновлювати лише те, що необхідно.

...для цього був створений Virtual DOM!

Virtual DOM створений, щоб постійне оновлення DOM стало більш продуктивним. На відміну від звичайного та Shadow DOM, Virtual DOM не офіційна специфікація, а скоріше новий метод взаємодії з DOM.

Virtual DOM можна розглядати, як копію звичайного DOM, яку можна часто оновлювати. Після внесення усіх змін до Virtual DOM, ми бачимо, які зміни слід внести у DOM та здійснити їх більш направлено та ефективно.

Як виглядає Virtual DOM?

«Віртуальний» DOM додає загадковості своєю назвою. Насправді, це звичайний об'єкт JavaScript.

Ще раз поглянемо на дерево DOM, яке ми створили:

Що таке Virtual DOM?

Його можна представити як JavaScript об'єкт:

const vdom = {
    tagName: "html",
    children: [
        { tagName: "head" },
        {
            tagName: "body",
            children: [
                {
                    tagName: "ul",
                    attributes: { "class": "list" },
                    children: [
                        {
                            tagName: "li",
                            attributes: { "class": "list__item" },
                            textContent: "List item"
                        } // end li
                    ]
                } // end ul
            ]
        } // end body
    ]
} // end html

Ми можемо вважати цей об'єкт нашим Virtual DOM. Подібно до звичайного DOM, тут бачимо об'єктне представлення вмісту HTML-документу. Але це простий об'єкт JavaScript, тому ми можемо часто маніпулювати ним, не звертаючись до фактичного DOM без потреби.

Набагато зручніше працювати з меншими частинами Virtual DOM. Наприклад, можемо працювати над компонентом list, що відповідатиме нашому невпорядкованому списку.

const list = {
    tagName: "ul",
    attributes: { "class": "list" },
    children: [
        {
            tagName: "li",
            attributes: { "class": "list__item" },
            textContent: "List item"
        }
    ]
};

Під капотом Virtual DOM

Ми ознайомились з виглядом Virtual DOM. Дізнаємось тепер як він розв'язує проблеми продуктивності та зручності.

Як вже згадувалось, ми можемо використовувати Virtual DOM, щоб виділити конкретні самостійні зміни, які необхідно внести у DOM. Повернемося до прикладу з невпорядкованим списком і внесемо ті ж зміни, що і з DOM API.

Спочатку ми зробимо копію Virtual DOM з усіма змінами, які ми хочемо зробити. Оскільки для цього нам не потрібен DOM API, ми просто створюємо новий об'єкт.

const copy = {
    tagName: "ul",
    attributes: { "class": "list" },
    children: [
        {
            tagName: "li",
            attributes: { "class": "list__item" },
            textContent: "List item one"
        },
        {
            tagName: "li",
            attributes: { "class": "list__item" },
            textContent: "List item two"
        }
    ]
};

Тут copy використовується для створення так званого diff між початковим Virtual DOM (у нашому випадку list) та оновленим. diff виглядатиме приблизно так:

const diffs = [
    {
        newNode: { /* нова версія першого елементу списку */ },
        oldNode: { /* початкова версія першого елементу списку */ },
        index: /* індекс елементу у батьківському списку дочірніх вузлів */
    },
    {
        newNode: { /* другий елемент списку*/ },
        index: { /* */ }
    }
]

diff містить інструкції з оновлення фактичного DOM. Після того, як усі diff зібрано, ми можемо внести лише необхідні зміни у DOM.

Наприклад, ми могли б циклічно обходити кожен diff та додавати новий дочірній елемент або оновлювати старий залежно від визначення diff.

const domElement = document.getElementsByClassName("list")[0];

diffs.forEach((diff) => {

    const newElement = document.createElement(diff.newNode.tagName);
    /* Додамо арибути ... */
    
    if (diff.oldNode) {
        // Якщо це стара версія, замінюємо на нову
        domElement.replaceChild(diff.newNode, diff.index);
    } else {
        // Якщо немає старої версії, створюємо новий вузол
        domElement.appendChild(diff.newNode);
    }
})

Зверніть увагу, що це спрощена версія. Насправді, Virtual DOM має ще безліч можливостей, які ця стаття не охоплює.

Virtual DOM та фреймворки

Частіше, робота з Virtual DOM відбувається через фреймворки, а не безпосередньо, як у прикладі.

Бібліотеки та фреймворки, на зразок React та Vue, використовують концепцію Virtual DOM для більш продуктивних змін у DOM. Наприклад, компонент list можна реалізувати в React таким чином:

import React from 'react';
import ReactDOM from 'react-dom';

const list = React.createElement("ul", { className: "list" },
    React.createElement("li", { className: "list__item" }, "List item")
);

ReactDOM.render(list, document.body);

Якщо б ми хотіли оновити наш список, ми переписали б шаблон списку та викликали ReactDOM.render() знову, передавши вже оновлений список.

const newList = React.createElement("ul", { className: "list" },
    React.createElement("li", { className: "list__item" }, "List item one"),
    React.createElement("li", { className: "list__item" }, "List item two");
);

setTimeout(() => ReactDOM.render(newList, document.body), 5000);

Оскільки React використовує Virtual DOM, при повторному відображенні цілого шаблону, оновлюються лише змінені частини. Якщо ми звернемося до інструментів розробника, коли здійснюються зміни, ми побачимо конкретні елементи та конкретні частини елементів, що змінюються.

Що таке Virtual DOM?

DOM vs Virtual DOM

Нагадаємо, що Virtual DOM — інструмент, що дозволяє взаємодіяти з елементами DOM простіше та ефективніше. Virtual DOM представлено у вигляді об'єкта Javascript, який ми можемо змінювати так часто, як нам потрібно. Зміни, здійснені над об'єктом накопичуються, а фактичний DOM оновлюється направлено та рідшe.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.7K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація