Frontend Development
Performance Optimization
Techniques and strategies for optimizing application performance
Performance Optimization
Performance optimization ensures applications are fast, responsive, and efficient.
Web Performance Metrics
Core Web Vitals
- LCP (Largest Contentful Paint): < 1.5s
- FID (First Input Delay): < 100ms
- CLS (Cumulative Layout Shift): < 0.1
Other Key Metrics
- FCP (First Contentful Paint)
- TTI (Time to Interactive)
- TBT (Total Blocking Time)
- Speed Index
Frontend Optimization
Code Splitting
// Dynamic imports
const Dashboard = dynamic(() => import('./Dashboard'), {
loading: () => <Skeleton />
})
// Route-based splitting
const routes = [
{
path: '/dashboard',
component: lazy(() => import('./Dashboard'))
}
]
Image Optimization
import Image from 'next/image'
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority
placeholder="blur"
blurDataURL="data:image/..."
/>
Lazy Loading
// Intersection Observer for lazy loading
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src
observer.unobserve(entry.target)
}
})
})
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img)
})
React Performance
Memoization
import { memo, useMemo, useCallback } from 'react'
// Component memoization
const ExpensiveComponent = memo(({ data }) => {
return <div>{/* ... */}</div>
})
// Value memoization
const sortedData = useMemo(() => {
return data.sort((a, b) => a.value - b.value)
}, [data])
// Function memoization
const handleClick = useCallback(() => {
console.log('clicked')
}, [])
Virtual Lists
import { FixedSizeList } from 'react-window'
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index]}</div>
)}
</FixedSizeList>
Bundle Optimization
Webpack/Next.js
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.optimization.splitChunks = {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
}
}
}
}
return config
}
}
Tree Shaking
// Import only what you need
import { debounce } from 'lodash-es'
// Instead of
import _ from 'lodash'
Backend Optimization
Database Optimization
Indexing
-- Add index for frequently queried columns
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- Composite index
CREATE INDEX idx_orders_user_status
ON orders(user_id, status);
Query Optimization
// ❌ N+1 query problem
const users = await User.findAll()
for (const user of users) {
const posts = await Post.findAll({ where: { userId: user.id } })
}
// ✅ Use eager loading
const users = await User.findAll({
include: [{ model: Post }]
})
Connection Pooling
const pool = new Pool({
max: 20,
min: 5,
idleTimeoutMillis: 30000
})
Caching Strategies
In-Memory Cache
import { LRUCache } from 'lru-cache'
const cache = new LRUCache({
max: 500,
ttl: 1000 * 60 * 5 // 5 minutes
})
async function getUser(id: string) {
const cached = cache.get(id)
if (cached) return cached
const user = await db.user.findUnique({ where: { id } })
cache.set(id, user)
return user
}
Redis Cache
import Redis from 'ioredis'
const redis = new Redis()
async function getCachedData(key: string) {
const cached = await redis.get(key)
if (cached) return JSON.parse(cached)
const data = await fetchData()
await redis.setex(key, 3600, JSON.stringify(data))
return data
}
HTTP Caching
// Next.js API Route
export async function GET() {
return new Response(JSON.stringify(data), {
headers: {
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=30'
}
})
}
API Optimization
Pagination
interface PaginationParams {
page: number
limit: number
}
async function getUsers({ page = 1, limit = 20 }: PaginationParams) {
const offset = (page - 1) * limit
const [users, total] = await Promise.all([
db.user.findMany({
skip: offset,
take: limit
}),
db.user.count()
])
return {
data: users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
}
}
GraphQL DataLoader
import DataLoader from 'dataloader'
const userLoader = new DataLoader(async (userIds) => {
const users = await db.user.findMany({
where: { id: { in: userIds } }
})
const userMap = new Map(users.map(u => [u.id, u]))
return userIds.map(id => userMap.get(id))
})
Network Optimization
Compression
// Enable gzip/brotli compression
import compression from 'compression'
app.use(compression())
CDN Usage
- Serve static assets from CDN
- Use edge caching
- Geographic distribution
HTTP/2 & HTTP/3
- Multiplexing
- Server push
- Header compression
Monitoring Performance
Web Vitals
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'
function sendToAnalytics(metric) {
const body = JSON.stringify(metric)
navigator.sendBeacon('/analytics', body)
}
getCLS(sendToAnalytics)
getFID(sendToAnalytics)
getFCP(sendToAnalytics)
getLCP(sendToAnalytics)
getTTFB(sendToAnalytics)
Performance API
const perfData = window.performance.timing
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart
console.log(`Page load time: ${pageLoadTime}ms`)
Tools
Analysis
- Chrome DevTools (Lighthouse)
- WebPageTest
- Bundle Analyzer
- React DevTools Profiler
Monitoring
- Sentry Performance
- New Relic
- DataDog
- Google Analytics
Best Practices
- Measure before optimizing
- Focus on user-perceived performance
- Optimize critical rendering path
- Minimize main thread work
- Use service workers for offline support
- Implement progressive enhancement
- Monitor performance in production
- Set performance budgets