ArchiveJournalJavaScript
JavaScript · December 28, 2023 · 14 min read

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

#javascript#patterns#async#functional-programming#performance
Sanyam Jain
Sanyam JainAuthor
Modern JavaScript Patterns for Better Code

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.

About the author

Full-Stack Developer specializing in Ruby on Rails and Next.js