
Performance Optimization
- 54 installs
- 19 repo stars
- Updated January 20, 2026
- miles990/claude-software-skills
Helps with ai & agent building tasks.
About
performance-optimization is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- performance-optimization
- AI & Agent Building
- AI-coding skill
Performance Optimization by the numbers
- 54 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #6,877 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/miles990/claude-software-skills --skill performance-optimizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 54 |
|---|---|
| repo stars | ★ 19 |
| Last updated | January 20, 2026 |
| Repository | miles990/claude-software-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Performance Optimization
Overview
Measure first, optimize second. This guide covers profiling techniques and optimization strategies.
---
Profiling First
The Golden Rule
1. Don't optimize prematurely
2. Measure before optimizing
3. Optimize the biggest bottleneck first
4. Measure again to verify improvementCPU Profiling (Node.js)
// Using Node.js built-in profiler
// Start with: node --prof app.js
// Process: node --prof-process isolate-*.log > profile.txt
// Or use clinic.js
// npm install -g clinic
// clinic doctor -- node app.js
// clinic flame -- node app.js
// Programmatic profiling
import { performance, PerformanceObserver } from 'perf_hooks';
const obs = new PerformanceObserver((items) => {
items.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('start');
await expensiveOperation();
performance.mark('end');
performance.measure('expensive-op', 'start', 'end');Memory Profiling
// Check memory usage
console.log(process.memoryUsage());
// {
// rss: 30000000, // Resident Set Size - total memory
// heapTotal: 7000000, // V8 heap total
// heapUsed: 5000000, // V8 heap used
// external: 800000 // C++ objects bound to JS
// }
// Take heap snapshot
const v8 = require('v8');
const fs = require('fs');
const snapshotFile = `heap-${Date.now()}.heapsnapshot`;
const snapshot = v8.writeHeapSnapshot(snapshotFile);
// Open in Chrome DevTools Memory tab---
Database Optimization
Query Optimization
-- ❌ Slow: SELECT * and no index
SELECT * FROM orders WHERE user_id = 123;
-- ✅ Better: Select only needed columns, with index
CREATE INDEX idx_orders_user_id ON orders(user_id);
SELECT id, total, status FROM orders WHERE user_id = 123;
-- ❌ N+1 query problem
-- For each user, query their orders (100 users = 101 queries)
SELECT * FROM users;
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM orders WHERE user_id = 2;
...
-- ✅ Single query with JOIN
SELECT u.*, o.* FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Or batch loading
SELECT * FROM orders WHERE user_id IN (1, 2, 3, ...);Explain Analyze
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id
ORDER BY order_count DESC
LIMIT 10;
-- Output shows:
-- - Execution plan (Seq Scan vs Index Scan)
-- - Estimated vs actual rows
-- - Time per operation
-- - Total execution timeIndex Strategies
-- Single column index
CREATE INDEX idx_users_email ON users(email);
-- Composite index (order matters!)
-- Good for: WHERE status = 'active' AND created_at > '2024-01-01'
CREATE INDEX idx_orders_status_created ON orders(status, created_at);
-- Partial index (smaller, faster for filtered queries)
CREATE INDEX idx_active_users ON users(email)
WHERE status = 'active';
-- Covering index (includes all needed columns)
CREATE INDEX idx_orders_user_covering ON orders(user_id)
INCLUDE (total, status, created_at);
-- When NOT to index:
-- - Small tables
-- - Columns with low cardinality (e.g., boolean)
-- - Frequently updated columns
-- - Write-heavy tables---
Caching
Cache Strategies
// Cache-aside pattern
async function getUser(id: string): Promise<User> {
// Try cache first
const cached = await cache.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Cache miss - fetch from DB
const user = await db.users.findById(id);
// Store in cache
if (user) {
await cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
}
return user;
}
// Write-through pattern
async function updateUser(id: string, data: Partial<User>): Promise<User> {
// Update DB
const user = await db.users.update(id, data);
// Update cache immediately
await cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
return user;
}Cache Invalidation
// Event-based invalidation
eventBus.on('user:updated', async (userId: string) => {
await cache.del(`user:${userId}`);
await cache.del(`user:${userId}:orders`);
});
// Tag-based invalidation
async function invalidateUserRelated(userId: string) {
const keys = await cache.keys(`*:user:${userId}:*`);
if (keys.length > 0) {
await cache.del(...keys);
}
}
// Version-based cache busting
const CACHE_VERSION = 'v2';
const cacheKey = `${CACHE_VERSION}:user:${id}`;Memoization
// Simple memoization
function memoize<T extends (...args: any[]) => any>(fn: T): T {
const cache = new Map();
return ((...args: Parameters<T>) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
}) as T;
}
// With TTL
function memoizeWithTTL<T extends (...args: any[]) => any>(
fn: T,
ttlMs: number
): T {
const cache = new Map<string, { value: any; expires: number }>();
return ((...args: Parameters<T>) => {
const key = JSON.stringify(args);
const cached = cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.value;
}
const result = fn(...args);
cache.set(key, { value: result, expires: Date.now() + ttlMs });
return result;
}) as T;
}---
Frontend Performance
Core Web Vitals
| Metric | Good | Description |
|---|---|---|
| LCP | < 2.5s | Largest Contentful Paint |
| INP | < 200ms | Interaction to Next Paint |
| CLS | < 0.1 | Cumulative Layout Shift |
Code Splitting
// React lazy loading
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
// Dynamic import for heavy libraries
async function processImage(file: File) {
const sharp = await import('sharp');
return sharp(file).resize(800).toBuffer();
}Image Optimization
<!-- Responsive images -->
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w
"
sizes="(max-width: 600px) 400px, 800px"
loading="lazy"
alt="Description"
/>
<!-- Modern formats with fallback -->
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="Description" />
</picture>Bundle Optimization
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
// Separate large libraries
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all',
},
},
},
},
};---
Backend Performance
Connection Pooling
// Database connection pool
import { Pool } from 'pg';
const pool = new Pool({
max: 20, // Maximum connections
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000, // Fail if can't connect in 2s
});
// Use pool, not individual connections
async function getUser(id: string) {
const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
return result.rows[0];
}
// HTTP connection keep-alive
import http from 'http';
const agent = new http.Agent({
keepAlive: true,
maxSockets: 50,
});
fetch('https://api.example.com', { agent });Async Processing
// Move slow operations out of request path
app.post('/api/orders', async (req, res) => {
// Quick: Create order
const order = await db.orders.create(req.body);
// Don't wait: Queue async tasks
await queue.add('send-confirmation-email', { orderId: order.id });
await queue.add('update-inventory', { items: order.items });
await queue.add('notify-warehouse', { orderId: order.id });
// Respond immediately
res.status(201).json(order);
});
// Process queue separately
queue.process('send-confirmation-email', async (job) => {
const order = await db.orders.findById(job.data.orderId);
await emailService.sendOrderConfirmation(order);
});Response Compression
import compression from 'compression';
import express from 'express';
const app = express();
// Compress responses > 1KB
app.use(compression({
threshold: 1024,
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));---
Algorithm Optimization
Time Complexity
// O(n²) → O(n) with Set
// Find duplicates
function hasDuplicates(arr: number[]): boolean {
// ❌ O(n²)
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) return true;
}
}
return false;
// ✅ O(n)
const seen = new Set<number>();
for (const num of arr) {
if (seen.has(num)) return true;
seen.add(num);
}
return false;
}
// O(n) → O(1) with Map
// Lookup by key
class UserCache {
// ❌ O(n) lookup
private users: User[] = [];
find(id: string) {
return this.users.find(u => u.id === id);
}
// ✅ O(1) lookup
private usersMap = new Map<string, User>();
findFast(id: string) {
return this.usersMap.get(id);
}
}Space vs Time Tradeoff
// Trade memory for speed: Precompute
class TaxCalculator {
private taxRates = new Map<string, number>();
constructor() {
// Precompute all tax rates
for (const state of US_STATES) {
this.taxRates.set(state, this.computeTaxRate(state));
}
}
// O(1) instead of O(complex calculation)
getTaxRate(state: string): number {
return this.taxRates.get(state) ?? 0;
}
}---
Monitoring Performance
// Application metrics
import { Counter, Histogram } from 'prom-client';
const httpRequestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests',
labelNames: ['method', 'route', 'status'],
buckets: [0.1, 0.5, 1, 2, 5]
});
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration
.labels(req.method, req.route?.path || 'unknown', res.statusCode.toString())
.observe(duration);
});
next();
});---
Related Skills
- [[database]] - Database optimization details
- [[frontend]] - Frontend performance
- [[monitoring-observability]] - Performance monitoring
Performance Optimization Reference
Detailed reference for profiling, benchmarking, and optimization techniques.
Profiling Tools
Node.js Profiling
# Built-in profiler
node --prof app.js
node --prof-process isolate-*.log > profile.txt
# Clinic.js suite
npm install -g clinic
clinic doctor -- node app.js # Identify bottlenecks
clinic flame -- node app.js # CPU flame graph
clinic bubbleprof -- node app.js # Async flow
clinic heapprofiler -- node app.js # Memory
# Chrome DevTools
node --inspect app.js
# Open chrome://inspectPython Profiling
# cProfile (built-in)
import cProfile
import pstats
profiler = cProfile.Profile()
profiler.enable()
# ... code to profile
profiler.disable()
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(20)
# Line profiler (pip install line_profiler)
# Add @profile decorator to functions
# Run: kernprof -l -v script.py
# Memory profiler (pip install memory_profiler)
from memory_profiler import profile
@profile
def memory_intensive_function():
data = [i ** 2 for i in range(1000000)]
return data
# Run: python -m memory_profiler script.pyGo Profiling
import (
"net/http"
_ "net/http/pprof"
"runtime/pprof"
)
// Enable HTTP profiling endpoint
func main() {
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
// ...
}
// Access at:
// http://localhost:6060/debug/pprof/
// http://localhost:6060/debug/pprof/heap
// http://localhost:6060/debug/pprof/goroutine
// CPU profile to file
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// Analyze: go tool pprof cpu.profRust Profiling
# Flamegraph
cargo install flamegraph
cargo flamegraph --bin myapp
# Perf (Linux)
perf record --call-graph dwarf ./target/release/myapp
perf report
# Valgrind (memory)
valgrind --tool=memcheck ./target/release/myapp
valgrind --tool=callgrind ./target/release/myappBenchmarking
Node.js Benchmarking
// Using Benchmark.js
import Benchmark from 'benchmark';
const suite = new Benchmark.Suite();
suite
.add('Array.push', function() {
const arr = [];
for (let i = 0; i < 1000; i++) arr.push(i);
})
.add('Array spread', function() {
let arr = [];
for (let i = 0; i < 1000; i++) arr = [...arr, i];
})
.on('cycle', (event) => {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest: ' + this.filter('fastest').map('name'));
})
.run({ async: true });
// Using built-in console.time
console.time('operation');
await expensiveOperation();
console.timeEnd('operation');
// High-resolution timing
const { performance } = require('perf_hooks');
const start = performance.now();
await expensiveOperation();
const duration = performance.now() - start;
console.log(`Duration: ${duration.toFixed(2)}ms`);Python Benchmarking
import timeit
# Simple timing
result = timeit.timeit(
'sum(range(1000))',
number=10000
)
print(f"Average: {result / 10000 * 1000:.4f}ms")
# Compare implementations
setup = '''
data = list(range(1000))
'''
implementations = {
'list_comp': '[x * 2 for x in data]',
'map': 'list(map(lambda x: x * 2, data))',
'loop': '''
result = []
for x in data:
result.append(x * 2)
''',
}
for name, code in implementations.items():
time = timeit.timeit(code, setup=setup, number=10000)
print(f"{name}: {time:.4f}s")
# Using pytest-benchmark
# pip install pytest-benchmark
def test_benchmark(benchmark):
result = benchmark(expensive_function, arg1, arg2)
assert result is not NoneGo Benchmarking
// benchmark_test.go
package main
import "testing"
func BenchmarkFunctionA(b *testing.B) {
for i := 0; i < b.N; i++ {
FunctionA()
}
}
func BenchmarkFunctionB(b *testing.B) {
for i := 0; i < b.N; i++ {
FunctionB()
}
}
// With memory allocation tracking
func BenchmarkWithAllocs(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
AllocatingFunction()
}
}
// Run: go test -bench=. -benchmemDatabase Query Optimization
PostgreSQL Query Analysis
-- Enable timing
\timing on
-- Explain analyze with buffers
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 10;
-- Check table statistics
SELECT
relname,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch
FROM pg_stat_user_tables
ORDER BY seq_tup_read DESC;
-- Find missing indexes
SELECT
schemaname,
relname,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch,
seq_tup_read / NULLIF(seq_scan, 0) as avg_seq_tup
FROM pg_stat_user_tables
WHERE seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 10;
-- Slow query log
-- postgresql.conf
-- log_min_duration_statement = 1000 -- Log queries > 1s
-- Check index usage
SELECT
indexrelname,
idx_scan,
idx_tup_read,
idx_tup_fetch
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;MySQL Query Analysis
-- Enable profiling
SET profiling = 1;
-- Run query
SELECT * FROM orders WHERE user_id = 123;
-- Show profile
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;
-- Explain with execution plan
EXPLAIN FORMAT=JSON
SELECT * FROM orders WHERE user_id = 123;
-- Check slow query log
-- my.cnf
-- slow_query_log = 1
-- slow_query_log_file = /var/log/mysql/slow.log
-- long_query_time = 1
-- Analyze table
ANALYZE TABLE orders;
-- Check index cardinality
SHOW INDEX FROM orders;Query Optimization Patterns
-- ❌ Using SELECT *
SELECT * FROM users WHERE id = 1;
-- ✅ Select only needed columns
SELECT id, name, email FROM users WHERE id = 1;
-- ❌ Using functions on indexed columns
SELECT * FROM orders WHERE YEAR(created_at) = 2024;
-- ✅ Use range instead
SELECT * FROM orders
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01';
-- ❌ Using OR with different columns
SELECT * FROM users
WHERE email = 'a@b.com' OR phone = '1234567890';
-- ✅ Use UNION for better index usage
SELECT * FROM users WHERE email = 'a@b.com'
UNION
SELECT * FROM users WHERE phone = '1234567890';
-- ❌ Using LIKE with leading wildcard
SELECT * FROM products WHERE name LIKE '%phone%';
-- ✅ Use full-text search
CREATE FULLTEXT INDEX idx_product_name ON products(name);
SELECT * FROM products WHERE MATCH(name) AGAINST('phone');
-- ❌ Selecting large result sets
SELECT * FROM logs WHERE level = 'info';
-- ✅ Use pagination
SELECT * FROM logs WHERE level = 'info'
ORDER BY id DESC
LIMIT 100 OFFSET 0;
-- ✅ Better: Keyset pagination
SELECT * FROM logs
WHERE level = 'info' AND id < 12345
ORDER BY id DESC
LIMIT 100;Caching Strategies
Cache Patterns Comparison
| Pattern | Description | Use Case | Consistency |
|---|---|---|---|
| Cache-Aside | App manages cache | General reads | Eventually |
| Read-Through | Cache manages reads | Transparent caching | Eventually |
| Write-Through | Cache manages writes | Read-heavy | Strong |
| Write-Behind | Async writes | Write-heavy | Eventually |
| Refresh-Ahead | Proactive refresh | Predictable access | Strong |
Redis Caching Implementation
import Redis from 'ioredis';
const redis = new Redis({
host: 'localhost',
port: 6379,
maxRetriesPerRequest: 3,
retryStrategy: (times) => Math.min(times * 50, 2000),
});
// Cache-aside with stale-while-revalidate
async function getWithSWR<T>(
key: string,
fetcher: () => Promise<T>,
ttlSeconds: number = 3600,
staleSeconds: number = 60
): Promise<T> {
const cached = await redis.get(key);
if (cached) {
const { data, timestamp } = JSON.parse(cached);
const age = Date.now() - timestamp;
// Fresh: return immediately
if (age < ttlSeconds * 1000) {
return data;
}
// Stale: return but refresh in background
if (age < (ttlSeconds + staleSeconds) * 1000) {
refreshInBackground(key, fetcher, ttlSeconds);
return data;
}
}
// Expired or miss: fetch and cache
const data = await fetcher();
await redis.set(
key,
JSON.stringify({ data, timestamp: Date.now() }),
'EX',
ttlSeconds + staleSeconds
);
return data;
}
async function refreshInBackground<T>(
key: string,
fetcher: () => Promise<T>,
ttlSeconds: number
) {
try {
const data = await fetcher();
await redis.set(
key,
JSON.stringify({ data, timestamp: Date.now() }),
'EX',
ttlSeconds
);
} catch (error) {
console.error('Background refresh failed:', error);
}
}
// Cache stampede prevention with mutex
async function getWithMutex<T>(
key: string,
fetcher: () => Promise<T>,
ttlSeconds: number = 3600
): Promise<T | null> {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const lockKey = `lock:${key}`;
const locked = await redis.set(lockKey, '1', 'EX', 10, 'NX');
if (locked) {
try {
const data = await fetcher();
await redis.set(key, JSON.stringify(data), 'EX', ttlSeconds);
return data;
} finally {
await redis.del(lockKey);
}
} else {
// Wait and retry
await new Promise((r) => setTimeout(r, 100));
return getWithMutex(key, fetcher, ttlSeconds);
}
}HTTP Caching Headers
// Cache-Control directives
const cacheStrategies = {
// Static assets (JS, CSS, images)
static: {
'Cache-Control': 'public, max-age=31536000, immutable',
},
// Dynamic but cacheable
dynamic: {
'Cache-Control': 'private, max-age=3600, must-revalidate',
'ETag': generateETag(content),
},
// Never cache
noCache: {
'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
// Stale-while-revalidate
swr: {
'Cache-Control': 'max-age=60, stale-while-revalidate=3600',
},
};
// ETag implementation
import crypto from 'crypto';
function generateETag(content: string | Buffer): string {
const hash = crypto.createHash('md5').update(content).digest('hex');
return `"${hash}"`;
}
// Conditional response
app.get('/api/resource/:id', async (req, res) => {
const data = await getResource(req.params.id);
const etag = generateETag(JSON.stringify(data));
if (req.headers['if-none-match'] === etag) {
return res.status(304).end();
}
res.set('ETag', etag);
res.set('Cache-Control', 'private, max-age=60');
res.json(data);
});Memory Optimization
Node.js Memory Management
// Monitor memory usage
function logMemoryUsage() {
const usage = process.memoryUsage();
console.log({
rss: `${(usage.rss / 1024 / 1024).toFixed(2)} MB`,
heapTotal: `${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`,
heapUsed: `${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`,
external: `${(usage.external / 1024 / 1024).toFixed(2)} MB`,
});
}
// Stream large files instead of loading into memory
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
import { createGzip } from 'zlib';
async function compressFile(input: string, output: string) {
await pipeline(
createReadStream(input),
createGzip(),
createWriteStream(output)
);
}
// Process large datasets in chunks
async function* processInChunks<T>(
items: T[],
chunkSize: number
): AsyncGenerator<T[], void, unknown> {
for (let i = 0; i < items.length; i += chunkSize) {
yield items.slice(i, i + chunkSize);
// Allow GC between chunks
await new Promise((r) => setImmediate(r));
}
}
async function processLargeDataset(items: any[]) {
for await (const chunk of processInChunks(items, 1000)) {
await processChunk(chunk);
}
}
// WeakMap for object metadata (auto garbage collected)
const metadata = new WeakMap<object, any>();
function attachMetadata(obj: object, data: any) {
metadata.set(obj, data);
}
// Object is garbage collected -> metadata is tooMemory Leak Detection
// Common leak patterns
// ❌ Leak: Growing array
const cache: any[] = [];
function processRequest(data: any) {
cache.push(data); // Never cleared
}
// ✅ Fix: LRU cache with size limit
import LRU from 'lru-cache';
const cache = new LRU({ max: 500 });
// ❌ Leak: Event listeners not removed
class Emitter {
handler = () => console.log('event');
subscribe() {
eventBus.on('event', this.handler);
}
// Missing unsubscribe!
}
// ✅ Fix: Always remove listeners
class Emitter {
handler = () => console.log('event');
subscribe() {
eventBus.on('event', this.handler);
}
unsubscribe() {
eventBus.off('event', this.handler);
}
}
// ❌ Leak: Closures holding references
function createHandler(largeData: Buffer) {
return function handler() {
// largeData is retained even if not used
console.log('handling');
};
}
// ✅ Fix: Don't capture unnecessary data
function createHandler() {
return function handler() {
console.log('handling');
};
}Network Optimization
Request Batching
// Batch multiple requests into one
class RequestBatcher<T, R> {
private queue: Array<{
key: T;
resolve: (value: R) => void;
reject: (error: Error) => void;
}> = [];
private timeout: NodeJS.Timeout | null = null;
constructor(
private batchFn: (keys: T[]) => Promise<R[]>,
private maxBatchSize: number = 100,
private maxWaitMs: number = 10
) {}
async load(key: T): Promise<R> {
return new Promise((resolve, reject) => {
this.queue.push({ key, resolve, reject });
if (this.queue.length >= this.maxBatchSize) {
this.flush();
} else if (!this.timeout) {
this.timeout = setTimeout(() => this.flush(), this.maxWaitMs);
}
});
}
private async flush() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
const batch = this.queue.splice(0, this.maxBatchSize);
if (batch.length === 0) return;
try {
const keys = batch.map((item) => item.key);
const results = await this.batchFn(keys);
batch.forEach((item, index) => item.resolve(results[index]));
} catch (error) {
batch.forEach((item) => item.reject(error as Error));
}
}
}
// Usage
const userLoader = new RequestBatcher<string, User>(
async (ids) => db.users.findByIds(ids)
);
// These get batched into one query
const [user1, user2, user3] = await Promise.all([
userLoader.load('1'),
userLoader.load('2'),
userLoader.load('3'),
]);Connection Pooling
// HTTP Agent pooling
import http from 'http';
import https from 'https';
const httpAgent = new http.Agent({
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000,
});
const httpsAgent = new https.Agent({
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000,
});
// Use with fetch
fetch('https://api.example.com/data', {
agent: httpsAgent,
});
// Database connection pool
import { Pool } from 'pg';
const pool = new Pool({
host: 'localhost',
database: 'mydb',
max: 20, // Maximum pool size
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 5000, // Connection timeout
allowExitOnIdle: true, // Allow process to exit when idle
});
// Monitor pool
pool.on('connect', () => console.log('New connection'));
pool.on('remove', () => console.log('Connection removed'));
pool.on('error', (err) => console.error('Pool error', err));
console.log({
total: pool.totalCount,
idle: pool.idleCount,
waiting: pool.waitingCount,
});Frontend Performance Metrics
Web Vitals Measurement
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';
function sendToAnalytics(metric: any) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating,
id: metric.id,
navigationType: metric.navigationType,
});
// Use sendBeacon for reliability
if (navigator.sendBeacon) {
navigator.sendBeacon('/analytics', body);
} else {
fetch('/analytics', { body, method: 'POST', keepalive: true });
}
}
// Register observers
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);
// Custom metrics
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
});
observer.observe({ entryTypes: ['measure', 'resource', 'longtask'] });Performance Budget
// performance-budget.json
{
"resourceSizes": [
{
"resourceType": "script",
"budget": 300
},
{
"resourceType": "stylesheet",
"budget": 100
},
{
"resourceType": "image",
"budget": 500
},
{
"resourceType": "font",
"budget": 100
},
{
"resourceType": "total",
"budget": 1000
}
],
"resourceCounts": [
{
"resourceType": "script",
"budget": 10
},
{
"resourceType": "stylesheet",
"budget": 5
}
],
"timings": [
{
"metric": "first-contentful-paint",
"budget": 1500
},
{
"metric": "largest-contentful-paint",
"budget": 2500
},
{
"metric": "interactive",
"budget": 3000
},
{
"metric": "total-blocking-time",
"budget": 300
}
]
}Load Testing
k6 Load Test Script
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate } from 'k6/metrics';
const errorRate = new Rate('errors');
export const options = {
stages: [
{ duration: '30s', target: 20 }, // Ramp up
{ duration: '1m', target: 20 }, // Stay at 20
{ duration: '30s', target: 50 }, // Ramp up more
{ duration: '1m', target: 50 }, // Stay at 50
{ duration: '30s', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% under 500ms
errors: ['rate<0.1'], // Error rate under 10%
},
};
export default function () {
const res = http.get('http://localhost:3000/api/users');
const success = check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
errorRate.add(!success);
sleep(1);
}
// Run: k6 run load-test.jsReferences
| Tool | Purpose | URL |
|---|---|---|
| Clinic.js | Node.js profiling | https://clinicjs.org/ |
| Lighthouse | Web performance | https://developers.google.com/web/tools/lighthouse |
| k6 | Load testing | https://k6.io/ |
| pg_stat_statements | PostgreSQL analysis | https://www.postgresql.org/docs/current/pgstatstatements.html |
| Redis Insight | Redis debugging | https://redis.com/redis-enterprise/redis-insight/ |
| Webpack Bundle Analyzer | Bundle size | https://www.npmjs.com/package/webpack-bundle-analyzer |
Related skills
AI & Agent Buildingagents