Explore advanced JavaScript patterns and techniques that will make your code more maintainable and efficient.
Sanyam Jain

Introduction
Modern JavaScript offers powerful patterns and techniques that can significantly improve code quality, maintainability, and performance. Let's explore some of the most useful patterns every developer should know.
Async/Await Patterns
Error Handling with Async/Await
// Robust error handling pattern
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const userData = await response.json()
return { data: userData, error: null }
} catch (error) {
console.error('Failed to fetch user data:', error)
return { data: null, error: error.message }
}
}
Parallel Async Operations
// Execute multiple async operations in parallel
async function loadDashboardData(userId) {
const [userResult, postsResult, notificationsResult] = await Promise.allSettled([
fetchUserData(userId),
fetchUserPosts(userId),
fetchNotifications(userId)
])
return {
user: userResult.status === 'fulfilled' ? userResult.value : null,
posts: postsResult.status === 'fulfilled' ? postsResult.value : [],
notifications: notificationsResult.status === 'fulfilled' ? notificationsResult.value : []
}
}
Functional Programming Patterns
Composition and Currying
// Function composition
const pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value)
const addTax = (rate) => (price) => price * (1 + rate)
const addShipping = (cost) => (price) => price + cost
const formatCurrency = (price) => `$${price.toFixed(2)}`
const calculateTotal = pipe(
addTax(0.08),
addShipping(5.99),
formatCurrency
)
console.log(calculateTotal(100)) // "$113.99"
Module Patterns
ES6 Modules with Default and Named Exports
// utils/api.js
export const API_BASE_URL = 'https://api.example.com'
export const httpClient = {
async get(endpoint) {
const response = await fetch(`${API_BASE_URL}${endpoint}`)
return response.json()
},
async post(endpoint, data) {
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
return response.json()
}
}
export default httpClient
Observer Pattern
class EventEmitter {
constructor() {
this.events = {}
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data))
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback)
}
}
}
Performance Optimization Patterns
Debouncing and Throttling
// Debounce function
function debounce(func, wait) {
let timeout
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout)
func(...args)
}
clearTimeout(timeout)
timeout = setTimeout(later, wait)
}
}
// Throttle function
function throttle(func, limit) {
let inThrottle
return function(...args) {
if (!inThrottle) {
func.apply(this, args)
inThrottle = true
setTimeout(() => inThrottle = false, limit)
}
}
}
Memory Management
Proper memory management is crucial for performance:
- Remove event listeners when components unmount
- Clear intervals and timeouts
- Avoid memory leaks with closures
- Use WeakMap and WeakSet for temporary references
Conclusion
These modern JavaScript patterns will help you write more maintainable, efficient, and robust code. Practice implementing these patterns in your projects to become a more effective developer.
Full-Stack Developer specializing in Ruby on Rails and Next.js