Minimizing Reflows
Reflows happen when the browser recalculates layout. They're expensive and should be minimized.
What Triggers Reflow
// Reading layout properties triggers reflow
const width = element.offsetWidth;
const height = element.offsetHeight;
const rect = element.getBoundingClientRect();
const computed = window.getComputedStyle(element);
// Writing layout properties triggers reflow
element.style.width = '100px';
element.style.height = '200px';
element.style.position = 'absolute';
Layout Thrashing
// BAD: Alternating reads and writes
for (let i = 0; i < 100; i++) {
element.style.width = `${i}px`; // Write
console.log(element.offsetWidth); // Read - forces layout!
}
// GOOD: Batch reads, then batch writes
const width = element.offsetWidth; // Read once
for (let i = 0; i < 100; i++) {
element.style.width = `${width + i}px`; // Write
}
Minimize DOM Changes
// BAD: Multiple individual changes
document.body.appendChild(newDiv1);
document.body.appendChild(newDiv2);
document.body.appendChild(newDiv3);
// GOOD: Single batch change
const fragment = document.createDocumentFragment();
fragment.appendChild(newDiv1);
fragment.appendChild(newDiv2);
fragment.appendChild(newDiv3);
document.body.appendChild(fragment); // Single reflow
Use CSS Classes
// BAD: Multiple style changes
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';
element.style.padding = '10px';
// GOOD: Single class change
element.classList.add('active-state');
/* CSS handles the rest */
.active-state {
color: red;
background-color: blue;
font-size: 16px;
padding: 10px;
}
Document Fragments
DocumentFragment is a lightweight container for building DOM trees offline.
Why Fragments?
// BAD: Each appendChild triggers reflow
const list = document.querySelector('ul');
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
list.appendChild(li); // 1000 reflows!
}
// GOOD: Fragment batches updates
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li); // No reflow yet!
}
list.appendChild(fragment); // 1 reflow!
Creating Fragments
// Method 1: DocumentFragment
const fragment = document.createDocumentFragment();
// Method 2: Template element
const template = document.querySelector('#item-template');
const clone = template.content.cloneNode(true);
document.body.appendChild(clone);
// Method 3: Template literal
const html = `
<div class="item">
<h2>Title</h2>
<p>Content</p>
</div>
`;
const temp = document.createElement('div');
temp.innerHTML = html;
const fragment = temp.firstElementChild;
Practical Example
function renderList(items) {
const list = document.querySelector('#list');
const fragment = document.createDocumentFragment();
items.forEach(item => {
const li = document.createElement('li');
li.dataset.id = item.id;
li.innerHTML = `
<span class="name">${item.name}</span>
<button class="delete">X</button>
`;
fragment.appendChild(li);
});
// Single DOM update
list.innerHTML = ''; // Clear list
list.appendChild(fragment); // Add all items
}
Cloning Nodes
const original = document.querySelector('.item');
// Shallow clone (no children)
const shallow = original.cloneNode(false);
// Deep clone (with children)
const deep = original.cloneNode(true);
// Add to DOM
document.body.appendChild(deep);
Virtual Scrolling
Virtual scrolling renders only visible items, essential for large lists.
The Problem
// Rendering 10,000 items is slow and memory-intensive
const items = Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`
}));
// This is terrible for performance!
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item.name;
list.appendChild(li);
});
Basic Virtual Scroll Implementation
class VirtualScroll {
constructor(container, items, itemHeight = 30) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight);
// Create scroll container
this.scrollContent = document.createElement('div');
this.scrollContent.style.height = `${items.length * itemHeight}px`;
this.scrollContent.style.position = 'relative';
// Create visible container
this.visibleContainer = document.createElement('div');
this.visibleContainer.style.position = 'absolute';
this.visibleContainer.style.width = '100%';
this.scrollContent.appendChild(this.visibleContainer);
this.container.appendChild(this.scrollContent);
// Listen for scroll
this.container.addEventListener('scroll', () => this.render());
this.render();
}
render() {
const scrollTop = this.container.scrollTop;
const startIndex = Math.floor(scrollTop / this.itemHeight);
const endIndex = Math.min(startIndex + this.visibleCount, this.items.length);
// Update position
this.visibleContainer.style.top = `${startIndex * this.itemHeight}px`;
// Render only visible items
this.visibleContainer.innerHTML = '';
for (let i = startIndex; i < endIndex; i++) {
const div = document.createElement('div');
div.style.height = `${this.itemHeight}px`;
div.textContent = this.items[i].name;
this.visibleContainer.appendChild(div);
}
}
}
// Usage
const container = document.querySelector('#scroll-container');
const virtualScroll = new VirtualScroll(container, items, 30);
Windowing Libraries
// Popular virtual scrolling libraries:
// - react-window
// - react-virtualized
// - vue-virtual-scroll-list
// - tanstack-virtual
// React example with react-window
import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>
Item {index}
</div>
);
const VirtualList = () => (
<FixedSizeList
height={500}
width="100%"
itemCount={10000}
itemSize={35}
>
{Row}
</FixedSizeList>
);
Practice Problems
Create a reusable React component implementing DOM Performance. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for DOM Performance using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize DOM Performance for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What is layout thrashing?
2. What is a DocumentFragment?
3. Why use virtual scrolling?
4. How do you minimize DOM reflows?
Flashcards
Question
What is layout thrashing?
Click to reveal answer
Answer
Alternating DOM reads and writes that force the browser to recalculate layout multiple times.
Question
What is a DocumentFragment?
Click to reveal answer
Answer
A lightweight container for building DOM trees offline. Adding to it doesn't trigger reflows.
Question
What is virtual scrolling?
Click to reveal answer
Answer
A technique that renders only visible items in a large list, improving performance.
Question
How to batch DOM updates?
Click to reveal answer
Answer
Use DocumentFragment or string building, then add to DOM once. Avoid alternating reads/writes.
Question
What is DOM Performance?
Click to reveal answer
Answer
DOM Performance is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Minimize DOM reads and writes to reduce reflows
- 2.DocumentFragment allows offline DOM building
- 3.Virtual scrolling is essential for large lists
- 4.CSS classes are more performant than inline styles
- 5.Batch DOM operations for better performance
Interview Tips
- •Explain layout thrashing and how to avoid it
- •Show how to use DocumentFragment for batch updates
- •Discuss virtual scrolling implementation
- •Explain when to use DocumentFragment vs innerHTML
Cheat Sheet
DOM Performance Cheat Sheet
Minimizing Reflows
- Batch reads and writes
- Use CSS classes instead of inline styles
- Use DocumentFragment for batch updates
DocumentFragment
const frag = document.createDocumentFragment();
frag.appendChild(el1);
frag.appendChild(el2);
document.body.appendChild(frag); // Single reflow
Layout Thrashing
// BAD
for (i) { write(); read(); }
// GOOD
const val = read();
for (i) { write(val); }
Virtual Scrolling
- Render only visible items
- Essential for 1000+ items
- Use libraries like react-window