Розуміння перетасування та перемальовування в браузері (переклад)

Нещодавно я дізнався про перетасування та перемальовування. Про те, як вони впливають на продуктивність вебсайтів. Я пишу цей допис, щоб дати уявлення про перетасування та перемальовування. Перед тим, як перейти до теми, зрозуміймо, як браузер візуалізує вебсайт.

Те, як браузер візуалізує вебсайт

Цей допис – переклад допису Гопалакрішнана для вебсайту DEV Community за 2020 рік. Посилання на оригінал – у кінці. Приємного прочитання.


  • Коли користувач заходить за URL, браузер отримує від сервера вихідний код HTML

  • Браузер розбирає вихідний код HTML та перетворює його на лексеми <, TagName, Attribute, AttributeValue, >

  • Лексеми перетворюються на вузли, вибудовується дерево DOM (об'єктної моделі документа)

  • На основі правил CSS генерується дерево CSSOM (об'єктної моделі CSS)

  • Дерева DOM та CSSOM об'єднуються в RenderTree (дерево візуалізації)

  • RenderTree конструюється так:

    • Почати з кореня дерева DOM та обчислити, які елементи видимі, а також їхні обчислені стилі

    • RenderTree ігнорує невидимі елементи штибу meta, script, link і display:none

    • Відбувається зіставлення видимих вузлів з відповідними правилами CSSOM та їхнє застосування

  • Перетасування: Обчислення позиції та розміру кожного видимого вузла

  • Перемалювання: тепер браузер малює renderTree на екрані

Перемалювання та перетасування

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

    • Наприклад: зміна visibility, кольору тла, контуру

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

І перетасування, і перемалювання є дорогими операціями

Згідно з Opera, більшість перетасувань, по суті, призводять до повторної візуалізації сторінки:

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

Ось відео візуалізації перетасування

Візуалізація перетасування

Що призводить до перетасування та перемальовування

  • Перетасування відбувається при додаванні, вилученні та оновленні вузлів DOM

  • Приховування елемента DOM за допомогою display: none призводить і до перетасування, і до перемальовування

  • Приховування елемента DOM за допомогою visibility: hidden призводить лише до перемальовування, оскільки не відбувається зміни компонування або позиції

  • Пересування чи анімування вузла DOM запускає перетасування та перемальовування

  • Зміна розміру вікна запускає перетасування

  • Зміна font-style змінює геометрію елемента. Це означає, що вона може впливати на позицію чи розмір інших елементів на сторінці, що вимагає від браузера виконати перетасування. Після завершення цих операцій компонування всі пошкоджені пікселі потребують перемальовування

  • Додавання чи вилучення списків стилів призводить до перетасування та перемальовування

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

var bodyStyle = document.body.style; // кеш

bodyStyle.padding = "20px"; // перетасування, перемальовування
bodyStyle.border = "10px solid red"; // перетасування, перемальовування

bodyStyle.color = "blue"; // лише перемальовування, розміри не змінюються
bstyle.backgroundColor = "#cc0000"; // перемальовування

bodyStyle.fontSize = "2em"; // перетасування, перемальовування

// новий елемент DOM – перетасування, перемальовування
document.body.appendChild(document.createTextNode("Привіт!"));

Мінімізація перетасувань і перемальовувань

Стратегія зниження негативного впливу перетасувань і перемальовувань на користувацький досвід полягає в тому, щоб мати менше перетасувань і перемальовувань, а також менше запитів до інформації про стилі, щоб браузер міг оптимізувати перетасування. Як це зробити?

  • Не змінюйте окремі стилі, один за одним. Найкраще для ментального здоров'я та подальшої підтримки коду – змінювати імена класів, а не стилі. Якщо стилі динамічні, редагуйте властивість cssText

// погано
var left = 10,
  top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

// краще
el.className += " theclassname";

// або, коли top і left обчилюються динамічно...

// краще
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
  • Виконуйте зміни DOM пакетами

    • Використовуйте documentFragment для зберігання тимчасових змін

    • Клонуйте, оновіть, замініть вузол

    • Приховайте елемент за допомогою display: none (1 перетасування, 1 перемальовування), внесіть 100 змін, відновіть відображення (всього 2 перетасування, 2 перемальовування)

  • Не питайте про обчислені стилі раз за разом, збережіть їх у змінній

    • Багато читань і записів (наприклад, для властивості height елемента)

    • Записи, потім читання з DOM, раз за разом, призводять до перетасувань документа

    • Прочитати (з кешу), записати (інвалідувати компонування), прочитати (запустити компонування).

    • Щоб виправити: спершу все прочитати, потім все записати

Chrome Tool Performance

Chrome надає чудовий інструмент, що допомагає зрозуміти, що відбувається з кодом, скільки є перетасувань (компонувань) і перемальовування, а також інші подробиці про пам'ять, події і т.д.

Поганий код

var box1Height = document.getElementById("box1").clientHeight;
document.getElementById("box1").style.height = box1Height + 10 + "px";

var box2Height = document.getElementById("box2").clientHeight;
document.getElementById("box2").style.height = box2Height + 10 + "px";

var box3Height = document.getElementById("box3").clientHeight;
document.getElementById("box3").style.height = box3Height + 10 + "px";

var box4Height = document.getElementById("box4").clientHeight;
document.getElementById("box4").style.height = box4Height + 10 + "px";

var box5Height = document.getElementById("box5").clientHeight;
document.getElementById("box5").style.height = box5Height + 10 + "px";

var box6Height = document.getElementById("box6").clientHeight;
document.getElementById("box6").style.height = box6Height + 10 + "px";

Оптимізований код

var box1Height = document.getElementById("box1").clientHeight;
var box2Height = document.getElementById("box2").clientHeight;
var box3Height = document.getElementById("box3").clientHeight;
var box4Height = document.getElementById("box4").clientHeight;
var box5Height = document.getElementById("box5").clientHeight;
var box6Height = document.getElementById("box6").clientHeight;

document.getElementById("box1").style.height = box1Height + 10 + "px";
document.getElementById("box2").style.height = box2Height + 10 + "px";
document.getElementById("box3").style.height = box3Height + 10 + "px";
document.getElementById("box4").style.height = box4Height + 10 + "px";
document.getElementById("box5").style.height = box5Height + 10 + "px";
document.getElementById("box6").style.height = box6Height + 10 + "px";

Додаткові джерела


Переклад виконано для посилання зі сторінки “Перемальовування глосарію WebDoky, українського проєкту перекладу MDN Web Docs українською. Оригінал статті на вебсайті DEV Community

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Віталій Перегончук
Віталій Перегончук@negativo_ua

1.2KПрочитань
5Автори
19Читачі
На Друкарні з 15 квітня

Більше від автора

Вам також сподобається

Коментарі (1)

а ще це дуже погано впливає на СЕО

Вам також сподобається