091
LVL 04 — SENIOR-IN-TRAININGSESSION 091DAY 91

PERFORMANCE PROFILING

🎫 PIXELCRAFT-077
Performance | 🔴 Expert | Priority: 🔴 Critical

Mobile users report sluggish interactions: slider adjustments lag, gallery scroll stutters, canvas redraws drop below 30fps. Profile the app systematically and fix the top 3 bottlenecks.
CONCEPTS.UNLOCKED
🔥
Chrome Performance Tab
Record, flame chart, long tasks. Hit Record, interact with the app, stop. The flame chart shows exactly where time is spent. Red blocks = long tasks (>50ms) that block the main thread.
🧠
Memory Profiling
Heap snapshots, memory leaks, GC pressure. Take snapshots over time. Objects growing = leak. Event listeners not cleaned up, intervals not cleared — they accumulate silently.
🎞️
requestAnimationFrame
Sync with the browser's render cycle. The browser repaints at 60fps (16.6ms per frame). rAF fires right before each repaint — the perfect time to update visuals. Never use setInterval for animation.
⏱️
Debounce vs Throttle
Debounce: wait until user stops. Throttle: fire at a fixed rate. Debounce search input (wait 300ms after last keystroke). Throttle scroll/resize handlers (fire at most once per 16ms).
📊
Performance Budgets
Set limits: TTI < 3s, bundle < 200KB, 60fps. A budget turns performance from "try to be fast" into a measurable constraint. Exceed the budget → the build fails. No regressions.
🏠
Lighthouse Scores
Performance, Accessibility, Best Practices, SEO. Automated audit in DevTools. Gives a score 0–100 with specific recommendations. Run before and after optimization — measure the impact.
HANDS-ON.TASKS
01
Record & Read a Performance Trace

Open DevTools → Performance → Record → interact with the app (drag sliders, scroll gallery, draw on canvas) → Stop. Read the flame chart: identify long tasks (>50ms blocks the main thread). Find the top 3 offenders: filter reapplication, gallery rendering, state serialization.

02
Fix #1: Throttle Filter Slider
// ❌ Before: fires on every pixel // of slider movement (100+ times/drag) slider.addEventListener('input', applyFilters); // ✅ After: throttle to 60fps function throttle( fn: Function, limit: number ) { let lastCall = 0; return function(...args: any[]) { const now = Date.now(); if (now - lastCall >= limit) { lastCall = now; fn(...args); } }; } slider.addEventListener('input', throttle(applyFilters, 16)); // ~60fps
03
Fix #2: Virtualize the Gallery
// ❌ Before: renders ALL 500 thumbnails // (500 DOM nodes, most offscreen) // ✅ After: only render visible items import { useVirtualizer } from '@tanstack/react-virtual'; function VirtualizedGallery({ images }: { images: Image[] }) { const parentRef = useRef(null); const virtualizer = useVirtualizer({ count: images.length, getScrollElement: () => parentRef.current, estimateSize: () => 200, }); return ( <div ref={parentRef} className="h-full overflow-auto"> <div style={{ height: `${virtualizer.getTotalSize()}px`, position: 'relative', }}> {virtualizer.getVirtualItems() .map(virtualItem => ( <div key={virtualItem.key} style={{ position: 'absolute', top: `${virtualItem.start}px`, height: `${virtualItem.size}px`, width: '100%', }}> <ImageCard image={images[ virtualItem.index]} /> </div> ))} </div> </div> ); }
500 images but only ~8 visible? Only render 8 DOM nodes. As the user scrolls, old nodes are recycled for new items. The DOM stays tiny no matter how many images exist.
04
Fix #3: Memory Leak in useEffect
// Take heap snapshots over time: // objects growing = leak // ❌ Common leaks: useEffect(() => { const interval = setInterval( checkStatus, 1000); window.addEventListener( 'resize', handleResize); socket.on('update', handleUpdate); // No cleanup! These accumulate // on every re-render. }); // ✅ Proper cleanup: useEffect(() => { const interval = setInterval( checkStatus, 1000); window.addEventListener( 'resize', handleResize); socket.on('update', handleUpdate); return () => { clearInterval(interval); window.removeEventListener( 'resize', handleResize); socket.off('update', handleUpdate); }; }, []);
05
Lighthouse Audit & Performance Budgets
// Run Lighthouse: DevTools → Lighthouse // Score before AND after optimization // Performance budgets: First Contentful Paint: < 1.5s Largest Contentful Paint: < 2.5s Cumulative Layout Shift: < 0.1 Total Blocking Time: < 200ms Bundle size (gzipped): < 200KB
06
Close the Ticket
git switch -c perf/PIXELCRAFT-077-profiling git add src/ git commit -m "Fix 3 perf bottlenecks: throttle + virtualize + leak (PIXELCRAFT-077)" git push origin perf/PIXELCRAFT-077-profiling # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Amdahl's Law: always optimize the biggest bottleneck.

If 80% of time is spent in filter processing, optimizing everything else can only improve total time by 20%. Profile first. Guess never.

// Amdahl's Law applies everywhere:

Parallel computing
  Speedup limited by the serial portion
  10% serial → max 10× speedup
  with infinite cores

Business optimization
  Fix the biggest constraint first
  "Theory of Constraints" — Goldratt

System design
  The bottleneck determines throughput
  Scaling the non-bottleneck = waste

// The performance methodology:
1. Measure (profile)
2. Identify hotspot
3. Optimize
4. Measure again
5. Repeat

// Never optimize without measuring.
// "Premature optimization is the
// root of all evil." — Knuth
"Performance Lab"
[A]Add React.memo() to expensive components: ImageCard, FilterPicker, Toolbar. Use React DevTools Profiler to measure re-renders before and after. Only memoize components that actually re-render unnecessarily.
[B]Implement code splitting with React.lazy() and Suspense: load the editor on demand, not on initial page load. Measure the bundle size reduction and FCP improvement.
[C]Research: what is the RAIL model? (Response < 100ms, Animation < 16ms, Idle < 50ms, Load < 1s). How does Chrome's Performance tab map to RAIL? Write a performance audit document for PixelCraft.
REF.MATERIAL
ARTICLE
Chrome Developers
Official guide to the Performance tab: recording, flame charts, main thread activity, long tasks, and frame rendering analysis.
DEVTOOLSOFFICIALESSENTIAL
VIDEO
Google Chrome
Performance budgets, Core Web Vitals, and practical optimization strategies. The Google-recommended approach to web performance.
PERFORMANCECORE VITALS
ARTICLE
Tanner Linsley
Virtualize any list, grid, or table. Only render visible items. The standard solution for large lists in React.
VIRTUALIZATIONREACT
ARTICLE
Google
Response, Animation, Idle, Load: the four pillars of user-centric performance. Target metrics for each category.
RAILTHEORYESSENTIAL
VIDEO
Jack Herrington
Profiling React apps: React DevTools Profiler, useMemo, useCallback, React.memo, virtualization, and code splitting.
REACTPROFILING
// LEAVE EXCITED BECAUSE
You have a systematic methodology for performance. No guessing. Profile → flame chart → fix the hotspot → verify. Gallery went from stuttering to butter-smooth. Lighthouse score jumped 30 points.