Розкрито таємниці порівняння віртуальних DOM: що порівнює React та чому це корисно
Зрозумійте, що насправді таке віртуальний DOM у React, як процес узгодження порівнює два дерева елементів, які зміни відбуваються на етапі комітування та звідки походить покращення продуктивності.
Інтерфейси постійно змінюються: з’являється сповіщення, кнопка перемикається, лічильник збільшується, список оновлюється. Кожна така зміна мусить потрапити до DOM браузера, а необережне оновлення DOM — це надійний спосіб зробити сторінку повільною. Відповіддю React є віртуальний DOM разом із кроком порівняння під назвою приведення до узгодженості. У цій статті пояснюється, що React зберігає в пам’яті, як він визначає зміни та чому це допомагає, щоб ви могли правильно оцінювати оновлення за допомогою точної уявної моделі.
Чому пряме записування в DOM є дорогим
До появи React оновлення UI були імперативними: знайти вузол та змінити його.
document.getElementById("title").innerText = "Hello";
Це підходить для невеликої сторінки. Коли сотні чи тисячі елементів часто змінюються, це стає як повільним, так і складним для керування, адже зміна в DOM може змусити браузер переробити:
- розрахунок стилів та макету
- перерозмітку навколишнього контенту
Щоразу браузер заново обчислює розташування елементів, їхні розміри та пікселі, які потрібно перемалювати. Ця робота значно складніша, ніж створення чи порівняння об’єктів JavaScript. Крім того, багато фрагментів коду, які незалежно впливають на DOM, ускладнюють синхронізацію екрана зі станом додатку.
Що насправді є Віртуальним DOM
Справжній DOM
Справжній DOM — це динамічна деревоподібна структура, яку браузер створює з маркапу, де кожен елемент відповідає окремому вузлу. Навіть це:
<body>
<h1>Hello</h1>
</body>
перетворюється на внутрішнє дерево, пов’язане з розміткою та процесом малювання, і часте змінення цього дерева спричиняє виконання складних операцій, про які йшлося вище.
Віртуальне представлення
Віртуальний DOM часто називають легкою копією справжнього DOM. Точніше кажучи, це опис того, як має виглядати інтерфейс: звичайні об’єкти, які повертають компоненти під час відображення. React спочатку оновлює цей опис, а вже потім впливає на браузер. Один елемент виглядає приблизно так:
{
type: "h1",
props: {
children: "Hello"
}
}
Такі об’єкти дешево створювати та порівнювати, тому React може визначити, що змінилося, перш ніж виконувати будь-які операції з справжнім DOM. JSX — це просто синтаксис для їх створення.
Під час першого відображення такого компонента:
function App() {
return <h1>Hello World</h1>;
}
React створює віртуальну структуру, генерує відповідні вузли DOM та вставляє їх у сторінку. Тепер обидві структури збігаються, і інтерфейс стає видимим.
Пізніше обробник кліку може оновити стан:
setCount(count + 1);
або батьківський елемент передає нові властивості. Це сигналізує про те, що частина інтерфейсу може потребувати змін. React не оновлює DOM негайно; він планує нове відображення, а оновлення від однієї й тієї самої події зазвичай об’єднуються в одну групу.
Під час цього відображення React знову викликає компонент та отримує нову структуру, тож тепер він містить як попередню, так і нову версії. Стара структура:
<h1>Hello</h1>
Нова структура:
<h1>Hello Omer</h1>
Завдання полягає у тому, щоб точно визначити, що змінилося.
Узгодження: як працює процес порівняння
Узгодження означає порівняння попередньої віртуальної структури з новою; сам процес порівняння зазвичай називається diffing. Для кожної позиції React перевіряє, чи змінився елемент, залишився незмінним чи був доданий/видалений. Концептуально:
Old Tree VS New Tree
Метою є найменший набір змін, які перетворюють старий інтерфейс користувача на новий. Повноцінне порівняння дерев буде занадто повільним, тому React використовує дві евристики. Якщо змінюється тип елемента, наприклад з div на span, React замінює весь піддерево замість того, щоб порівнювати його дочірні елементи. У списках він порівнює дочірні елементи за значенням key, тому важливі стабільні ключі: вони повідомляють React, що елемент переміщений, а не замінений.
Коли змінюється лише текст
Раніше:
<h1>Hello</h1>
Після:
<h1>Hello Omer</h1>
<h1> має той самий тип у тому ж місці; відрізняється лише його текст. Тому React зберігає існуючий вузол DOM та оновлює лише вузол тексту, замість того щоб створювати елемент заново. Основою оптимізації є пропуск усіх операцій, які не є абсолютно необхідними.
Етап комітування: застосування лише змінених елементів
Після порівняння React записує отримані зміни у справжній DOM:
- оновлення тексту
- встановлення або видалення атрибутів
- додавання нових елементів
- видалення елементів, які зникли
Це і є етап комітування — єдиний момент, коли React впливає на DOM, і він змінює лише те, що позначено у результатах порівняння. Потім браузер перерисовує вплинуті ділянки. Щоб детальніше дізнатися про процес переходу від коміту до пікселів, ознайомтесь з нашим посібником про відображення даних у React від оновлень стану до пікселів екрана.
Звідки походить покращення продуктивності
Перевага полягає у меншій кількості дорогих операцій з DOM. Замість того, щоб перебудовувати все заново, React порівнює старий та новий описи, обчислює мінімальні відмінності та впливає лише на зачеплені вузли. Оскільки порівняння об’єктів значно дешевше, ніж зміна DOM, це зазвичай приносить користь у великих додатках.
Два застереження забезпечують об’єктивність цього підходу. Віртуальний DOM не є за своєю суттю швидшим за ретельно налаштований код DOM; його цінність полягає у можливості писати декларативний UI, при цьому отримуючи ефективні оновлення. Крім того, відображення не є безкоштовним: React все одно викликає ваші компоненти та порівнює їхній вихід, тому уникнення непотрібних повторних відображень залишається важливим.
Основні висновки
- Віртуальний DOM — це набір звичайних об’єктів, які описують бажаний інтерфейс та створюються заново під час кожного відображення.
key як скорочень.