Claude
Skills
Sign in
Back

browser-runtime-performance-profiling

Included with Lifetime
$97 forever

Browser runtime profiling with Chrome DevTools and Core Web Vitals optimization. PROACTIVELY activate for: (1) Using Chrome Performance panel, (2) Analyzing flame charts, (3) Diagnosing long tasks, (4) Core Web Vitals optimization, (5) Memory profiling. Triggers: "devtools", "performance panel", "lighthouse", "flame graph", "jank", "long task", "fps", "layout thrashing", "core web vitals"

Productivity

What this skill does


# Browser Runtime Performance Profiling

This skill provides mastery of Chrome DevTools Performance panel to diagnose and resolve runtime performance issues, including rendering bottlenecks, long tasks that block the main thread, and memory leaks.

## Recording a Performance Profile

Proper setup ensures useful, actionable profiling data.

### Setup Steps

1. **Use Incognito Mode**: Extensions can skew results
2. **Open DevTools**: F12 or Cmd+Option+I (Mac)
3. **Navigate to Performance Panel**: Top navigation bar
4. **Configure Settings** (gear icon):
   - Enable "Screenshots": Visual timeline of page changes
   - Set "Network": "Slow 3G" to simulate slow connections
   - Set "CPU": "4x slowdown" to amplify bottlenecks
5. **Click Record** (circle icon)
6. **Perform Actions**: Interact with the page
7. **Stop Recording**: Click stop or press Cmd/Ctrl+E

### Best Practices

- **Profile production builds**: Development builds have extra overhead
- **Record 5-10 seconds**: Enough data without overwhelming detail
- **Focus on user interactions**: Scrolling, clicking, typing
- **Use throttling**: CPU and network throttling reveals issues on slower devices

### Quick Keyboard Shortcuts

- **Cmd/Ctrl+E**: Start/stop recording
- **Cmd/Ctrl+Shift+E**: Reload and record
- **WASD**: Navigate timeline (W/S = zoom, A/D = pan)

## Analyzing the Flame Chart

The flame chart is the primary tool for diagnosing runtime issues. It shows main thread activity over time.

### Reading the Flame Chart

**Vertical axis**: Call stack depth (top = innermost function)
**Horizontal axis**: Time
**Colors**:
- **Yellow**: JavaScript execution
- **Purple**: Rendering and layout
- **Green**: Painting
- **Gray**: Other (idle, system)

### Identifying Long Tasks

**Long Task**: Any task that blocks the main thread for > 50ms

**Visual indicator**: Yellow blocks with a **red triangle** in the upper right corner

```
Example:
┌────────────────────────────────┐
│ ▲ (Long Task)                  │ ← Red triangle
│ evaluateScript     248ms       │ ← Problem!
│  └─ processData                │
│      └─ heavyCalculation       │
└────────────────────────────────┘
```

**Impact**: Blocks user interactions (scrolling, clicking). Aim for tasks < 50ms.

**Solution**: Break up work with:
- `setTimeout` for splitting tasks
- `requestIdleCallback` for low-priority work
- Web Workers for heavy computation
- React `useTransition` for large UI updates

### Identifying Layout Thrashing

**Layout Thrashing**: Reading layout properties immediately after changing them, forcing synchronous layout recalculation.

**Visual indicator**: Multiple purple "Layout" blocks in rapid succession

```
Example flame chart:
JavaScript
  └─ updateElements
      ├─ element.style.height = '100px'   (Write)
      ├─ Layout (Forced)                   ← Purple block
      ├─ element.offsetHeight              (Read)
      ├─ element.style.width = '200px'     (Write)
      └─ Layout (Forced)                   ← Purple block
```

**Solution**: Batch reads and writes

```js
// BAD: Layout thrashing
elements.forEach(el => {
  el.style.height = el.offsetWidth + 'px' // Read, then write
})

// GOOD: Batch reads, then writes
const widths = elements.map(el => el.offsetWidth) // All reads
elements.forEach((el, i) => {
  el.style.height = widths[i] + 'px' // All writes
})
```

### Identifying Expensive Scripts

**Visual indicator**: Wide yellow blocks labeled "Evaluate Script" or "Function Call"

**Impact**: Delays page interactivity (FID/INP)

**Solution**:
- Code splitting (load less JavaScript upfront)
- Lazy load non-critical features
- Optimize algorithms (reduce time complexity)
- Offload to Web Workers

### Identifying Excessive Rendering

**Visual indicator**: Many purple "Recalculate Style" or "Layout" blocks

**Causes**:
- Large DOM trees
- Complex CSS selectors
- Unnecessary re-renders in React
- CSS animations triggering layout

**Solution**:
- Simplify CSS selectors
- Use `transform` and `opacity` for animations (these don't trigger layout)
- Minimize DOM depth
- Memoize React components

## Interpreting Core Web Vitals

Core Web Vitals are user-centric performance metrics.

### Largest Contentful Paint (LCP)

**Definition**: Time until the largest content element is rendered

**Target**: < 2.5 seconds

**Where to Find**: "Timings" section, blue "LCP" marker

**Common Causes**:
- Slow server response (TTFB)
- Large, unoptimized images
- Render-blocking CSS/JS
- Client-side rendering

**Solutions**:
- Optimize server response time
- Use next/image with priority attribute
- Inline critical CSS
- Server-side rendering (Next.js RSC)
- Preload LCP resource: `<link rel="preload" as="image" href="/hero.jpg">`

### Interaction to Next Paint (INP)

**Definition**: Time from user interaction to visual response

**Target**: < 200ms (good), < 500ms (acceptable)

**Where to Find**: "Experience" section when interacting

**Common Causes**:
- Long JavaScript tasks
- Excessive event handlers
- Slow React re-renders
- Main thread blocked

**Solutions**:
- Break up long tasks
- Debounce/throttle event handlers
- Use React `useTransition` for non-urgent updates
- Code splitting
- Web Workers for heavy computation

### Cumulative Layout Shift (CLS)

**Definition**: Sum of all unexpected layout shifts

**Target**: < 0.1

**Where to Find**: "Experience" section, red "Layout Shift" markers

**Common Causes**:
- Images without dimensions
- Ads/embeds without reserved space
- Web fonts causing FOIT/FOUT
- Dynamic content injection

**Solutions**:
- Always specify image width/height
- Reserve space for ads/embeds with CSS
- Use `font-display: optional` or preload fonts
- Avoid inserting content above existing content

## Using the Performance Monitor

Real-time graph of key metrics during interaction.

### Enable Performance Monitor

1. Open DevTools
2. Cmd/Ctrl+Shift+P (Command Palette)
3. Type "Show Performance Monitor"
4. Select from dropdown

### Key Metrics

- **CPU usage**: Spikes indicate heavy computation
- **JS heap size**: Increasing = potential memory leak
- **DOM Nodes**: High count = slow rendering
- **JS event listeners**: Too many = overhead
- **Layouts/sec**: High = layout thrashing
- **Style recalcs/sec**: High = CSS performance issues

### Using the Data

- **CPU consistently high**: Profile to find bottleneck
- **Heap size growing**: Take heap snapshot, find leaks
- **DOM nodes growing**: Check for detached nodes
- **High layouts/repaints**: Look for layout thrashing

## Memory Profiling

Identify memory leaks and excessive memory usage.

### Taking a Heap Snapshot

1. **Open DevTools** → **Memory** panel
2. Select **Heap snapshot**
3. Click **Take snapshot**
4. Interact with the page
5. Take another snapshot
6. Compare snapshots

### Finding Memory Leaks

**Detached DOM Nodes**: Nodes removed from DOM but still in memory

**How to Find**:
1. Take heap snapshot
2. Search for "Detached"
3. Expand "Detached HTMLDivElement" (or other elements)
4. Check "Retainers" to see what's holding the reference

**Common Causes**:
- Event listeners not removed
- Closures capturing DOM nodes
- Global variables referencing DOM
- Third-party libraries not cleaning up

**Solution**:
```js
// BAD: Event listener not removed
useEffect(() => {
  window.addEventListener('resize', handleResize)
  // Missing cleanup!
}, [])

// GOOD: Cleanup function
useEffect(() => {
  window.addEventListener('resize', handleResize)
  return () => window.removeEventListener('resize', handleResize)
}, [])
```

### Allocation Timeline

Shows memory allocations over time.

1. **Memory** panel → **Allocation timeline**
2. Click **Record**
3. Interact with the page
4. Stop recording
5. Blue bars show allocations

**Look for**: Steadily increasing allocations (potential leak)

## Lighthouse Integration

Automated performance audits providing actionable recommendations.

### Running Lighthouse

1. Open DevTools → **Lighthouse** panel
2. Select **Performance** category
3. Click

Related in Productivity