Last updated
JavaScript Performance Analyzer Examples
The JavaScript Performance Analyzer identifies performance anti-patterns, memory leaks, and optimization opportunities in your code. Below are examples of common issues it detects and how to fix them.
Example: DOM Layout Thrashing
// ⚠ Performance issue — layout thrashing:
function resizeElements(elements) {
elements.forEach(el => {
const width = el.offsetWidth; // forces layout recalculation
el.style.width = width * 2 + 'px'; // triggers layout
const height = el.offsetHeight; // forces layout again!
el.style.height = height * 2 + 'px';
});
}
// ✓ Fixed — batch reads then writes:
function resizeElements(elements) {
// Read phase (all reads together)
const dimensions = elements.map(el => ({
width: el.offsetWidth,
height: el.offsetHeight
}));
// Write phase (all writes together)
elements.forEach((el, i) => {
el.style.width = dimensions[i].width * 2 + 'px';
el.style.height = dimensions[i].height * 2 + 'px';
});
}
// Analyzer output:
// Line 3: Reading offsetWidth inside a write loop causes layout thrashing.
// Estimated impact: HIGH — can cause 60fps → 5fps on large lists.
Example: Memory Leak — Event Listeners
// ⚠ Memory leak — listener never removed:
class DataPoller {
constructor() {
this.data = new Array(100000).fill('data');
window.addEventListener('resize', this.handleResize.bind(this));
// handleResize holds reference to 'this', preventing GC
}
handleResize() {
console.log('resized');
}
// No cleanup method!
}
// ✓ Fixed — remove listener on cleanup:
class DataPoller {
constructor() {
this.data = new Array(100000).fill('data');
this._handleResize = this.handleResize.bind(this);
window.addEventListener('resize', this._handleResize);
}
handleResize() {
console.log('resized');
}
destroy() {
window.removeEventListener('resize', this._handleResize);
this.data = null;
}
}
// Analyzer output:
// Line 3: Event listener added but never removed. Memory leak risk.
// Each DataPoller instance will retain 100,000 items in memory indefinitely.
Example: Inefficient Loop
// ⚠ Performance issue — array.length accessed every iteration:
function sumValues(items) {
let total = 0;
for (let i = 0; i < items.length; i++) { // items.length recalculated each time
total += items[i].value;
}
return total;
}
// ✓ Fixed — cache length:
function sumValues(items) {
let total = 0;
const len = items.length; // cached once
for (let i = 0; i < len; i++) {
total += items[i].value;
}
return total;
}
// Even better — use reduce:
const sumValues = items => items.reduce((sum, item) => sum + item.value, 0);
// Analyzer output:
// Line 3: Array.length accessed in loop condition. Cache it for better performance.
// Impact: LOW for small arrays, MEDIUM for arrays > 10,000 items.
Example: O(n²) Complexity
// ⚠ Performance issue — O(n²) nested loop:
function findDuplicates(arr) {
const duplicates = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) { // nested loop!
if (arr[i] === arr[j] && !duplicates.includes(arr[i])) {
duplicates.push(arr[i]);
}
}
}
return duplicates;
}
// Time: O(n²) — 1,000 items = 1,000,000 comparisons
// ✓ Fixed — O(n) with Set:
function findDuplicates(arr) {
const seen = new Set();
const duplicates = new Set();
for (const item of arr) {
if (seen.has(item)) duplicates.add(item);
else seen.add(item);
}
return [...duplicates];
}
// Time: O(n) — 1,000 items = 1,000 operations
// Analyzer output:
// Line 4: Nested loop creates O(n²) complexity. Use a Set or Map for O(n) solution.
// Estimated impact: CRITICAL for large arrays.
Example: React Unnecessary Re-renders
// ⚠ Performance issue — missing memoization:
function ProductList({ products, onSelect }) {
// This function is recreated on every render
const handleClick = (id) => {
onSelect(id);
};
// This calculation runs on every render
const total = products.reduce((sum, p) => sum + p.price, 0);
return (
<ul>
{products.map(p => (
<ProductItem key={p.id} product={p} onClick={handleClick} />
))}
<li>Total: {total}</li>
</ul>
);
}
// ✓ Fixed — memoize callback and expensive calculation:
function ProductList({ products, onSelect }) {
const handleClick = useCallback((id) => {
onSelect(id);
}, [onSelect]); // only recreated when onSelect changes
const total = useMemo(
() => products.reduce((sum, p) => sum + p.price, 0),
[products] // only recalculated when products changes
);
return (
<ul>
{products.map(p => (
<ProductItem key={p.id} product={p} onClick={handleClick} />
))}
<li>Total: {total}</li>
</ul>
);
}
// Analyzer output:
// Line 3: Function created inside component without useCallback.
// Line 7: Expensive calculation without useMemo.
Example: String Concatenation in Loop
// ⚠ Performance issue — string concatenation in loop:
function buildHtml(items) {
let html = '';
for (const item of items) {
html += `<li>${item.name}</li>`; // creates new string each iteration
}
return `<ul>${html}</ul>`;
}
// ✓ Fixed — use array join:
function buildHtml(items) {
const parts = items.map(item => `<li>${item.name}</li>`);
return `<ul>${parts.join('')}</ul>`;
}
// Analyzer output:
// Line 4: String concatenation in loop creates O(n²) memory allocations.
// Use Array.join() for O(n) performance.
Performance Report Summary
File: dashboard.js
Critical issues (fix immediately):
Line 45: O(n²) nested loop — use Map/Set instead
Line 112: Synchronous XMLHttpRequest blocks main thread
High priority:
Line 23: DOM layout thrashing in animation loop
Line 67: Memory leak — event listener never removed
Medium priority:
Line 89: Missing useCallback on event handler
Line 134: Expensive calculation without useMemo
Low priority:
Line 201: Array.length not cached in loop
Line 245: String concatenation in loop (small array, low impact)
Estimated improvement after fixes:
Main thread blocking: -850ms
Memory usage: -45MB over 10 minutes
React re-renders: -60%
Paste your JavaScript code to get a prioritized list of performance issues with specific fix recommendations and estimated impact for each issue.