PatternsObservability
Performance Profiling Advanced (Chrome DevTools)
Master Chrome DevTools for performance analysis
Chrome DevTools Performance tab reveals exactly where your app spends time. Learn to identify bottlenecks and optimize effectively.
Recording a Profile
1. Open DevTools (F12)
2. Performance tab
3. Click Record (Ctrl+E)
4. Interact with your app
5. Stop recording
6. Analyze flame chartUnderstanding the Flame Chart
Main Thread:
├── Task (yellow) - JavaScript execution
├── Rendering (purple) - Layout, paint
├── Idle (white) - Waiting
└── Long Task (red corner) - > 50ms
GPU Thread:
└── Rasterization (green) - Drawing pixelsIdentifying Long Tasks
// Detect long tasks
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
// Warn if task > 50ms
if (entry.duration > 50) {
console.warn(`Long task detected: ${entry.duration}ms`, entry);
// Log to analytics
logMetric({
name: 'long_task',
duration: entry.duration,
attribution: entry.attribution,
});
}
});
});
observer.observe({ entryTypes: ['longtask'] });Performance Marks & Measures
// Mark important moments
performance.mark('component-render-start');
ReactDOM.render(<App />, root);
performance.mark('component-render-end');
// Measure duration
performance.measure(
'component-render',
'component-render-start',
'component-render-end'
);
// Get measurement
const measure = performance.getEntriesByName('component-render')[0];
console.log(`Render: ${measure.duration.toFixed(2)}ms`);User Timing API
// Wrap expensive operations
export async function profiledFetch(url: string) {
const start = `fetch-${url}-start`;
const end = `fetch-${url}-end`;
performance.mark(start);
try {
const response = await fetch(url);
const data = await response.json();
performance.mark(end);
performance.measure(`fetch-${url}`, start, end);
return data;
} catch (error) {
performance.mark(end);
performance.measure(`fetch-${url}-error`, start, end);
throw error;
}
}Analyzing Specific Functions
// Profile function execution
export function profileFunction<T extends (...args: any[]) => any>(
fn: T,
name: string
): T {
return ((...args: Parameters<T>) => {
const start = performance.now();
const result = fn(...args);
const duration = performance.now() - start;
if (duration > 16) { // Frame budget
console.warn(`${name} took ${duration.toFixed(2)}ms`);
}
return result;
}) as T;
}
// Usage
const processData = profileFunction(
(data: any[]) => data.map(item => transform(item)),
'processData'
);Timeline Visualization
// Custom timeline events
console.time('data-processing');
processLargeDataset();
console.timeEnd('data-processing');
// Grouped timings
console.group('API Calls');
console.time('fetch-users');
await fetchUsers();
console.timeEnd('fetch-users');
console.time('fetch-posts');
await fetchPosts();
console.timeEnd('fetch-posts');
console.groupEnd();Best Practices
- Record real user flows - Don't profile in isolation
- Disable extensions - They skew results
- Use CPU throttling - Test on slow devices (4x slowdown)
- Look for red flags - Long tasks, forced layouts
- Measure before/after - Verify optimizations work
- Profile production builds - Dev mode is slower
- Use Lighthouse - Automated suggestions
- Check frame rate - Aim for 60fps (16.6ms per frame)
Use Chrome DevTools Performance tab to find bottlenecks—measure, optimize, repeat!