TGViewer
Дивовижний світ веброзробки Дивовижний світ веброзробки @babichdev · 2.91K subscribers
Post #155 2.15K
"…Я повільно додаю в DOM новий елемент. Потім ще один. І ще один. Мене вже не зупинити — один за одним нові вузли додаються, змушуючи DOM здригатися та щоразу перезапускати reflow на кожен дотик мого нескінченного циклу. "Досить!" — закричав би він, якби міг кричати, але натомість лише покірно раз за разом перебудовує layout, сповільнюючись усе сильніше, та врешті решт, досягнувши найвищої точки завантажености, просто зависає…"

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

І в цій невдячній справі нам стане в нагоді DocumentFragment. Це такий собі віртуальний контейнер, який існує лише в памʼяті, що дозволяє проводити різні маніпуляції зі своїм вмістом за допомогою DOM API, а потім безболісно вставляти цей вміст в реальний DOM за одну ітерацію.

Так, DocumentFragment ініціює лише один цикл repaint/reflow незалежно від того, скільки вузлів та елементів в ньому зараз знаходиться.

const fragment = document.createDocumentFragment();

// а хоч 10 000 юзерів
for (const user of users) {
const li = document.createElement('li');
li.textContent = user.name;
fragment.appendChild(li);
}

document
.querySelector('ul')
.appendChild(fragment);


Звичайно, це не означає, що бравзер однаково швидко опрацює вставку одного елемента і десяти тисяч елементів через фрагмент. Але вважайте, що саме reflow може суттєво вдарити по вашій швидкодії. І чим менше ми його ініціюємо, тим краще.

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

Взагалі, DocumentFragment — це саме DOM Node, а не DOM Element. Це означає, що він має appendChild, querySelector, cloneNode, але не має innerHtml, classList, id, style. Іноді і я про це забуваю, марно намагаючись щось там учудити з innerHtml.

До речі, fragment.parentNode === null, бо він не є частиною DOM.

З цікавих особливостей також можна відмітити, що при вставці фрагменту в DOM його дочірні вузли переміщаються в реальне дерево, а не копіюються. childNodes.length === 0 і робіть що хочете. Однак якщо ви використаєте cloneNode(true) на фрагменті, то отримаєте повноцінну копію без втрати вмісту цього фрагмента. Тож, якщо ви захочете вставити фрагмент в декілька місць, клонування — ваш вибір.

А взагалі ця поведінка притаманна саме методам append та appendChild, а не самому фрагменту.

Так, ну й властивість .content template-елемента вже є DocumentFragment, саме через це скрізь рекомендують спочатку склонувати його вміст, а потім уже з ним працювати. Інакше попсуєте оригінал.

Ще варто відмітити, що позаяк фрагмент не може бути частиною DOM, то поки вміст знаходиться в ньому, той не наслідує стилі документа. Такий елемент може мати лише явно присвоєні стилі, або через inline style, або через властивість style DOM-обʼєкта. Але тут є ще одне але. Якщо це стилі блочні — розміри, відступи, оце все, то вони не впливатимуть на елемент, і той же getBoundingClientRect поверне всі нулі. Причина проста — елемент не в реальному DOM, і не пройшов layout-фазу.

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

Взагалі, фрагмент надзвичайно зручно використовувати тоді, коли нам треба зробити багато маніпуляцій над DOM-вузлами. Наприклад, ви їх можете "висмикнути" з реального дерева, помістити у фрагмент, поробити усе, що вам треба: додати мільйон event listeners, позмінювати усі атрибути на світі, повпихувати в усі вузли новий контент, а потім просто одним махом вставити усе назад. І це вартуватиме вас лише одного циклу reflow.

🌐 MDN: DocumentFragment

🔥 Було цікаво? Тисніть вподобайку, поширюйте сей допис, а за це вам від мене величезна подяка і цьом у лобіка.

@babichdev
  • 🔥 90
  • ❤ 26
More from @babichdev
  1. Sep 30, 2026Товариство, запрошую вас цієї суботи, 3 жовтня, на Fwdays Tech Summit — онлайн конференцію…
  2. Sep 28, 2026#збір_на_авто_для_21 Товариство, почнімо тиждень з доброго діла. Я би дуже хотів, аби ми ц…
  3. Sep 27, 2026Знайшов своє старезне резюме. Аж пустив скупу сльозу за тими часами, коли навіть з таким м…
  4. Sep 25, 2026Днями на редіті побачив допис, в якому автор питав, чому його лічильник часу на сторінці з…
  5. Sep 23, 2026Який ШІ найкращий для навчання? Відповідь проста — той, з яким ви чогось навчились. ШІ це…
  6. Sep 18, 2026Оце я, канєшна, провтикав. Конфа завтра, 19 вересня. Ще встигаєте взяти квиточок.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →