JavaScript Performance
Optimize your JavaScript code for better speed and efficiency
⚡ Why JavaScript Performance Matters?
Performance optimization makes your web applications faster, more responsive, and provides better user experience. Small optimizations can make a big difference in how your code runs!
// Slow: Creating objects in a loop
for (let i = 0; i < 1000; i++) {
const obj = { value: i }; // Creates 1000 objects
}
// Fast: Reuse objects when possible
const reusableObj = { value: 0 };
for (let i = 0; i < 1000; i++) {
reusableObj.value = i; // Reuses same object
}
Performance Optimization Areas
Loop Optimization
Make loops run faster
DOM Optimization
Efficient DOM manipulation
Memory Management
Prevent memory leaks
Code Splitting
Load code efficiently
🔹 Loop Performance Optimization
Loops are often performance bottlenecks. Here's how to optimize them:
Loop Optimization Tips:
- Cache array length to avoid recalculation
- Use appropriate loop type for the task
- Avoid function calls inside loops
- Break early when possible
// ❌ Slow: Recalculates length every iteration
const items = new Array(10000).fill(0);
for (let i = 0; i < items.length; i++) {
// Process item
items[i] = i * 2;
}
// ✅ Fast: Cache the length
const items2 = new Array(10000).fill(0);
const length = items2.length; // Cache length
for (let i = 0; i < length; i++) {
items2[i] = i * 2;
}
// ✅ Even better: Use built-in methods when appropriate
const items3 = new Array(10000).fill(0);
const processed = items3.map((_, index) => index * 2);
// ✅ Best for simple operations: for...of
const numbers = [1, 2, 3, 4, 5];
let sum = 0;
for (const num of numbers) {
sum += num; // Clean and fast
}
Performance Impact:
Cached length: ~20% faster
Built-in methods: Often 2-3x faster
for...of: Most readable for simple cases
🔹 DOM Performance Optimization
DOM operations are expensive. Minimize and batch them for better performance:
// ❌ Slow: Multiple DOM queries and updates
function updateList(items) {
const list = document.getElementById('list');
// Slow: Query DOM in loop
for (let i = 0; i < items.length; i++) {
const li = document.createElement('li');
li.textContent = items[i];
list.appendChild(li); // Slow: Multiple DOM updates
}
}
// ✅ Fast: Batch DOM operations
function updateListFast(items) {
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
// Build in memory first
for (let i = 0; i < items.length; i++) {
const li = document.createElement('li');
li.textContent = items[i];
fragment.appendChild(li);
}
// Single DOM update
list.appendChild(fragment);
}
// ✅ Even faster: Use innerHTML for simple cases
function updateListFastest(items) {
const list = document.getElementById('list');
list.innerHTML = items.map(item => `${item} `).join('');
}
// ✅ Cache DOM elements
const cachedElements = {
list: document.getElementById('list'),
button: document.getElementById('button'),
input: document.getElementById('input')
};
// Use cached elements instead of querying every time
cachedElements.button.addEventListener('click', () => {
const value = cachedElements.input.value;
// Process value...
});
🔹 Memory Management
Prevent memory leaks and optimize memory usage:
// ❌ Memory leak: Event listeners not removed
function createButton() {
const button = document.createElement('button');
function handleClick() {
console.log('Button clicked');
}
button.addEventListener('click', handleClick);
document.body.appendChild(button);
// Memory leak: listener not removed when button is removed
}
// ✅ Proper cleanup
function createButtonProper() {
const button = document.createElement('button');
function handleClick() {
console.log('Button clicked');
}
button.addEventListener('click', handleClick);
document.body.appendChild(button);
// Return cleanup function
return function cleanup() {
button.removeEventListener('click', handleClick);
button.remove();
};
}
// ❌ Memory leak: Circular references
function createCircularReference() {
const obj1 = {};
const obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1; // Circular reference
return obj1;
}
// ✅ Avoid circular references
function createProperReference() {
const parent = { children: [] };
const child = { parent: parent };
parent.children.push(child);
// No circular reference - child references parent, but parent has array
return parent;
}
// ✅ Use WeakMap for object associations
const objectData = new WeakMap();
function associateData(obj, data) {
objectData.set(obj, data); // Automatically cleaned up when obj is garbage collected
}
🔹 Function Performance
Optimize function calls and reduce overhead:
Function Optimization Tips:
- Avoid creating functions in loops: Define once, reuse many times
- Use arrow functions carefully: They don't have their own 'this'
- Memoize expensive calculations: Cache results
- Debounce frequent calls: Limit execution frequency
// ❌ Slow: Creating functions in loops
const buttons = document.querySelectorAll('button');
buttons.forEach((button, index) => {
button.addEventListener('click', function() { // New function each time
console.log(`Button ${index} clicked`);
});
});
// ✅ Fast: Reuse function with event delegation
document.addEventListener('click', function(event) {
if (event.target.tagName === 'BUTTON') {
const index = Array.from(buttons).indexOf(event.target);
console.log(`Button ${index} clicked`);
}
});
// ✅ Memoization for expensive calculations
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key); // Return cached result
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// Example: Expensive fibonacci calculation
const fibonacci = memoize(function(n) {
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(40)); // Fast after first calculation
// ✅ Debouncing for frequent events
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Use for search input
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(function(query) {
// Expensive search operation
console.log('Searching for:', query);
}, 300);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
🔹 Performance Measurement
Measure performance to identify bottlenecks:
// ✅ Measure execution time
function measurePerformance(name, fn) {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${name} took ${end - start} milliseconds`);
return result;
}
// Example usage
const result = measurePerformance('Array processing', () => {
const arr = new Array(100000).fill(0);
return arr.map(x => x * 2);
});
// ✅ Use console.time for simple measurements
console.time('Loop performance');
for (let i = 0; i < 1000000; i++) {
// Some operation
}
console.timeEnd('Loop performance');
// ✅ Performance monitoring
function monitorFunction(fn, name) {
return function(...args) {
const start = performance.now();
const result = fn.apply(this, args);
const duration = performance.now() - start;
if (duration > 10) { // Log slow operations
console.warn(`Slow operation: ${name} took ${duration}ms`);
}
return result;
};
}
// Wrap slow functions
const slowFunction = monitorFunction(expensiveCalculation, 'expensiveCalculation');