Project 1: The Performance-First Dashboard
📋 Project Brief
Build a data-intensive monitoring dashboard that handles high-frequency updates (1,000+ data points/second) without dropping frames. This simulates real-world scenarios like stock exchanges, server farms, or IoT monitoring systems. The primary objective is to demonstrate mastery over the browser's main thread, memory management, and rendering pipeline.
🎯 Learning Objectives
- Understand the browser rendering pipeline (Style → Layout → Paint → Composite)
- Implement Virtual Scrolling to keep the DOM lean with 10,000+ rows
- Use Web Workers to offload heavy computation from the main thread
- Master
requestAnimationFramefor smooth, 60FPS visual updates - Build adaptive polling systems that respond to user activity
📐 Architecture Overview
The application consists of four major systems working together:
| System | Responsibility | Key Challenge |
|---|---|---|
| Data Layer | Fetches, buffers, and manages incoming data streams | Handling 1,000+ updates/second without memory leaks |
| Virtual Scroll Engine | Renders only visible rows in the viewport | Calculating row positions and recycling DOM nodes |
| Worker Thread | Sorts, filters, and aggregates data off the main thread | Serialization overhead of postMessage |
| Render Pipeline | Updates the UI at 60FPS using requestAnimationFrame | Batching DOM writes to avoid layout thrashing |
✅ Feature Requirements
Feature 1: Virtual Scrolling
What it does: Only renders the rows currently visible in the viewport, plus a small buffer above and below.
Acceptance Criteria:
- The dashboard must display a dataset of 10,000+ rows
- The DOM should never contain more than ~50 rendered row elements at any time
- Scrolling must remain smooth at 60FPS (use Chrome DevTools Performance tab to verify)
- The scrollbar height must accurately reflect the total number of rows
- Rapid scrolling (flicking) must not cause blank/white flashes
Technical Hints: Research "windowing" techniques. Calculate startIndex and endIndex from scrollTop, rowHeight, and viewportHeight. Use a container with a calculated total height to give the scrollbar the correct proportional size.
Feature 2: Memory Monitor Widget
What it does: A live widget displaying the app's current heap usage.
Acceptance Criteria:
- Display
usedJSHeapSize,totalJSHeapSize, andjsHeapSizeLimitin a human-readable format (MB) - Update every 2 seconds
- Show a visual progress bar that turns red when heap usage exceeds 80%
- Gracefully handle browsers that don't support
performance.memory(show "Not Supported")
Feature 3: Web Worker Processing
What it does: Offloads all data sorting, filtering, and aggregation to a background thread.
Acceptance Criteria:
- Clicking "Sort by Price" must NOT freeze the UI, even with 50,000 rows
- The Worker must accept messages like
{ type: "SORT", column: "price", direction: "asc" } - The Worker must post back the sorted result, which the main thread then renders
- Include a loading indicator while the Worker is processing
- The Worker file must be separate and independently testable
Feature 4: Theme Engine
What it does: Instant light/dark mode switching with zero flicker.
Acceptance Criteria:
- All colors must be defined as CSS Custom Properties (no hardcoded hex/rgb in components)
- Toggling the theme must update in under 16ms (one frame)
- The user's preference must persist in
localStorage - On first load, respect the system preference via
prefers-color-scheme
Feature 5: Dynamic Polling
What it does: Adapts the data-fetching interval based on user activity and tab visibility.
Acceptance Criteria:
- When the tab is active and the user is interacting: poll every 1 second
- When the tab is active but the user is idle (no mouse/keyboard for 30s): poll every 5 seconds
- When the tab is in the background (
visibilitychangeevent): poll every 30 seconds or pause entirely - Resuming the tab must immediately fetch the latest data
🏗️ Suggested File Structure
| File / Folder | Purpose |
|---|---|
src/components/VirtualList/ | The virtual scrolling engine component |
src/components/MemoryMonitor/ | The heap usage widget |
src/workers/dataWorker.js | The Web Worker for sorting/filtering |
src/hooks/usePolling.js | Custom hook for adaptive data fetching |
src/styles/theme.css | CSS Custom Properties for theming |
src/utils/generateData.js | Mock data generator for development |
📊 Performance Benchmarks (Pass/Fail)
| Metric | Target | How to Measure |
|---|---|---|
| Frame Rate during scroll | ≥ 55 FPS | Chrome DevTools → Performance → FPS meter |
| DOM Node Count | < 200 nodes in the list | DevTools → Elements → Count rendered rows |
| Heap Growth over 5 min | < 5MB increase | DevTools → Memory → Heap snapshot comparison |
| Sort 50K rows (Worker) | < 500ms | Console timer in Worker |
| Theme Switch | < 16ms | Performance.measure() around toggle |
🧪 Testing Checklist
- Unit test the virtual scroll index calculations (given scrollTop X, expect rows Y-Z)
- Unit test the Worker sorting logic independently
- Integration test: scrolling to the bottom loads the correct last row
- Accessibility: all interactive elements must be keyboard-navigable
- Lighthouse Performance score ≥ 95
🚀 Stretch Goals
- Add column resizing via drag handles
- Implement "sticky" header rows that remain visible during scroll
- Add a "CSV Export" button that generates a file from the current filtered view
- Implement sparkline mini-charts inside table cells