Front-end Engineering Lab

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 chart

Understanding 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 pixels

Identifying 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

  1. Record real user flows - Don't profile in isolation
  2. Disable extensions - They skew results
  3. Use CPU throttling - Test on slow devices (4x slowdown)
  4. Look for red flags - Long tasks, forced layouts
  5. Measure before/after - Verify optimizations work
  6. Profile production builds - Dev mode is slower
  7. Use Lighthouse - Automated suggestions
  8. Check frame rate - Aim for 60fps (16.6ms per frame)

Use Chrome DevTools Performance tab to find bottlenecks—measure, optimize, repeat!

On this page