PatternsObservability
CPU Profiling
Identify performance bottlenecks with CPU profiling
CPU profiling reveals which functions consume the most processing time. Essential for optimizing JavaScript performance.
Chrome DevTools CPU Profiler
1. DevTools → Performance tab
2. Record profile
3. Interact with app
4. Stop recording
5. Analyze "Bottom-Up" and "Call Tree" tabsJavaScript Profiling API
// Start profiling
console.profile('myProfile');
// Run expensive code
expensiveFunction();
// Stop profiling
console.profileEnd('myProfile');
// Results appear in DevTools Profiles tabFinding Hot Functions
// Measure function execution time
export function measurePerformance<T extends (...args: any[]) => any>(
fn: T,
label: string
): T {
return ((...args: Parameters<T>) => {
const start = performance.now();
const result = fn(...args);
const duration = performance.now() - start;
if (duration > 5) {
console.log(`⚠️ ${label}: ${duration.toFixed(2)}ms`);
}
return result;
}) as T;
}
// Usage
const processData = measurePerformance(
(items: Item[]) => items.map(transform),
'processData'
);React DevTools Profiler
import { Profiler, ProfilerOnRenderCallback } from 'react';
const onRenderCallback: ProfilerOnRenderCallback = (
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) => {
console.log(`${id} (${phase}) took ${actualDuration.toFixed(2)}ms`);
// Log slow renders
if (actualDuration > 16) {
logMetric({
component: id,
phase,
duration: actualDuration,
});
}
};
export function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<YourComponents />
</Profiler>
);
}Performance Budgets
// Set performance budgets
const BUDGETS = {
'data-processing': 50, // ms
'component-render': 16,
'api-call': 1000,
};
export function checkBudget(operation: string, duration: number) {
const budget = BUDGETS[operation];
if (budget && duration > budget) {
console.warn(
`Performance budget exceeded: ${operation} took ${duration.toFixed(2)}ms (budget: ${budget}ms)`
);
logMetric({
type: 'budget_exceeded',
operation,
duration,
budget,
overage: duration - budget,
});
}
}
// Usage
const start = performance.now();
processData();
checkBudget('data-processing', performance.now() - start);Optimizing Hot Paths
// ❌ Slow: Create new function every render
function Component({ items }: Props) {
return (
<ul>
{items.map(item => (
<li key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</li>
))}
</ul>
);
}
// ✅ Fast: Memoized handler
function Component({ items }: Props) {
const handleClick = useCallback((id: string) => {
// Handle click
}, []);
return (
<ul>
{items.map(item => (
<li key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</li>
))}
</ul>
);
}Best Practices
- Profile in production mode - Dev mode is slower
- Use CPU throttling - Test on slow devices
- Focus on hot paths - Optimize frequently called code
- Measure first - Don't optimize blindly
- Set budgets - Define acceptable performance
- Memoize expensive computations - useMemo, useCallback
- Defer non-critical work - requestIdleCallback
- Monitor in production - Track real user performance
CPU profiling reveals bottlenecks—measure before optimizing!