Writing Faster JavaScript
Performance optimization ensures your web applications run smoothly and respond quickly to user interactions.
Common performance issues include inefficient loops, excessive DOM manipulation, memory leaks, and blocking operations.
While premature optimization should be avoided, understanding performance fundamentals helps you write efficient code from the start.
// ❌ Inefficient: DOM queries in loop
for (let i = 0; i < 1000; i++) {
document.getElementById('result').innerHTML += i;
}
// ✅ Efficient: Cache DOM reference, build string first
const result = document.getElementById('result');
let html = '';
for (let i = 0; i < 1000; i++) {
html += i;
}
result.innerHTML = html;
// ✅ Even Better: Use array join
const result = document.getElementById('result');
const items = [];
for (let i = 0; i < 1000; i++) {
items.push(i);
}
result.innerHTML = items.join('');
// Debouncing: Limit function execution rate
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Usage: Don't run search on every keystroke
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(performSearch, 300);
searchInput.addEventListener('input', debouncedSearch);
// Use event delegation instead of multiple listeners
// ❌ Bad: Adding listener to each item
items.forEach(item => {
item.addEventListener('click', handleClick);
});
// ✅ Good: One listener on parent
parent.addEventListener('click', function(e) {
if (e.target.matches('.item')) {
handleClick(e);
}
});
// Lazy loading: Load images when needed
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
- Cache DOM References - Store element references instead of querying repeatedly
- Minimize DOM Manipulation - Batch changes, use DocumentFragment
- Debouncing/Throttling - Limit how often functions execute
- Event Delegation - Use parent listeners instead of many individual ones
- Lazy Loading - Load resources only when needed
- Avoid Memory Leaks - Remove event listeners, clear timers
- Use Efficient Loops - Cache array length, consider array methods
- Async Operations - Don't block main thread with heavy computation
- Code Splitting - Load only necessary code initially
Performance Comparison
<div class="performance-demo">
<h3>Performance Optimization</h3>
<div class="example">
<h4>1. DOM Manipulation Comparison</h4>
<button id="slowBtn">Slow Method (Direct DOM)</button>
<button id="fastBtn">Fast Method (Cached)</button>
<div id="perfOutput"></div>
<div id="domResult"></div>
</div>
<div class="example">
<h4>2. Debouncing Demo</h4>
<p>Type to see debouncing in action:</p>
<input type="text" id="normalInput" placeholder="Normal (executes every keystroke)">
<div id="normalCount">Executions: 0</div>
<input type="text" id="debouncedInput" placeholder="Debounced (300ms delay)">
<div id="debouncedCount">Executions: 0</div>
</div>
<div class="example">
<h4>3. Event Delegation</h4>
<button id="addItems">Add 100 Items</button>
<div id="itemsContainer"></div>
<div id="delegationOutput">Click count: 0</div>
</div>
</div>
Note: Measure First: Use browser DevTools Performance tab to identify actual bottlenecks before optimizing.
Note: Premature Optimization: Don't optimize everything - focus on code that actually impacts user experience.
Note: Trade-offs: Sometimes readable code is better than micro-optimized code. Balance performance with maintainability.