💎 Performance

Web Performance Optimization

Last updated: 2025-09-25 12:47:03

Web Performance Optimization

Comprehensive guide to optimizing web application performance including loading times, runtime performance, and user experience metrics.

Core Web Vitals Optimization

// Largest Contentful Paint (LCP) optimization
// 1. Optimize images
const optimizeImage = (imageSrc, options = {}) => {
  const {
    width = 800,
    quality = 85,
    format = 'webp'
  } = options;
  
  // Use modern image formats
  return `${imageSrc}?w=${width}&q=${quality}&f=${format}`;
};

// 2. Preload critical resources
const preloadCriticalResources = () => {
  const link = document.createElement('link');
  link.rel = 'preload';
  link.as = 'image';
  link.href = '/hero-image.webp';
  document.head.appendChild(link);
};

// 3. Lazy load non-critical images
const createLazyImageObserver = () => {
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.classList.remove('lazy');
        observer.unobserve(img);
      }
    });
  });
  
  document.querySelectorAll('img[data-src]').forEach(img => {
    imageObserver.observe(img);
  });
};

JavaScript Performance Optimization

// Debouncing and throttling
const debounce = (func, delay) => {
  let timeoutId;
  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

const throttle = (func, limit) => {
  let inThrottle;
  return function (...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
};

// Virtual scrolling for large lists
class VirtualList {
  constructor(container, items, itemHeight, visibleCount) {
    this.container = container;
    this.items = items;
    this.itemHeight = itemHeight;
    this.visibleCount = visibleCount;
    this.startIndex = 0;
    
    this.init();
  }
  
  init() {
    this.container.style.height = `${this.visibleCount * this.itemHeight}px`;
    this.container.style.overflow = 'auto';
    
    this.viewport = document.createElement('div');
    this.viewport.style.height = `${this.items.length * this.itemHeight}px`;
    this.viewport.style.position = 'relative';
    
    this.container.appendChild(this.viewport);
    this.container.addEventListener('scroll', this.handleScroll.bind(this));
    
    this.render();
  }
  
  handleScroll() {
    const scrollTop = this.container.scrollTop;
    const newStartIndex = Math.floor(scrollTop / this.itemHeight);
    
    if (newStartIndex !== this.startIndex) {
      this.startIndex = newStartIndex;
      this.render();
    }
  }
  
  render() {
    this.viewport.innerHTML = '';
    
    const endIndex = Math.min(
      this.startIndex + this.visibleCount + 2,
      this.items.length
    );
    
    for (let i = this.startIndex; i < endIndex; i++) {
      const item = document.createElement('div');
      item.style.position = 'absolute';
      item.style.top = `${i * this.itemHeight}px`;
      item.style.height = `${this.itemHeight}px`;
      item.textContent = this.items[i];
      
      this.viewport.appendChild(item);
    }
  }
}

Bundle Optimization Strategies

// Code splitting with dynamic imports
const loadFeature = async (featureName) => {
  try {
    const module = await import(`./features/${featureName}`);
    return module.default;
  } catch (error) {
    console.error(`Failed to load feature: ${featureName}`, error);
    throw error;
  }
};

// Route-based code splitting (React example)
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./pages/Home'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));

function App() {
  return (
    Loading...
}> } /> } /> } /> ); } // Tree shaking optimization // Import only what you need import { debounce } from 'lodash/debounce'; // ✅ Good // import * as _ from 'lodash'; // ❌ Bad // Use ES modules and avoid CommonJS export const utilities = { formatDate: (date) => date.toLocaleDateString(), capitalizeFirst: (str) => str.charAt(0).toUpperCase() + str.slice(1) };

Caching Strategies

// Service Worker for caching
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('v1').then(cache => {
      return cache.addAll([
        '/',
        '/styles/main.css',
        '/scripts/main.js',
        '/images/logo.png'
      ]);
    })
  );
});

self.addEventListener('fetch', event => {
  if (event.request.destination === 'image') {
    event.respondWith(
      caches.match(event.request).then(response => {
        return response || fetch(event.request).then(response => {
          const responseClone = response.clone();
          caches.open('images').then(cache => {
            cache.put(event.request, responseClone);
          });
          return response;
        });
      })
    );
  }
});

// HTTP caching headers (Express.js)
app.use('/static', express.static('public', {
  maxAge: '1y', // Cache static assets for 1 year
  etag: false,
  lastModified: false
}));

app.use('/api', (req, res, next) => {
  // Cache API responses for 5 minutes
  res.set('Cache-Control', 'public, max-age=300');
  next();
});

// Memory caching with TTL
class MemoryCache {
  constructor() {
    this.cache = new Map();
  }
  
  set(key, value, ttl = 300000) { // 5 minutes default
    const expiry = Date.now() + ttl;
    this.cache.set(key, { value, expiry });
    
    setTimeout(() => {
      this.cache.delete(key);
    }, ttl);
  }
  
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }
    
    return item.value;
  }
  
  clear() {
    this.cache.clear();
  }
}

Performance Monitoring

// Performance measurement
const measurePerformance = (name, fn) => {
  return async (...args) => {
    const start = performance.now();
    
    try {
      const result = await fn(...args);
      const end = performance.now();
      
      console.log(`${name} took ${end - start} milliseconds`);
      
      // Send to analytics
      if ('sendBeacon' in navigator) {
        navigator.sendBeacon('/api/metrics', JSON.stringify({
          name,
          duration: end - start,
          timestamp: Date.now()
        }));
      }
      
      return result;
    } catch (error) {
      const end = performance.now();
      console.error(`${name} failed after ${end - start} milliseconds:`, error);
      throw error;
    }
  };
};

// Core Web Vitals measurement
const measureWebVitals = () => {
  // Largest Contentful Paint
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('LCP:', entry.startTime);
    }
  }).observe({ entryTypes: ['largest-contentful-paint'] });
  
  // First Input Delay
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('FID:', entry.processingStart - entry.startTime);
    }
  }).observe({ entryTypes: ['first-input'] });
  
  // Cumulative Layout Shift
  let clsValue = 0;
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (!entry.hadRecentInput) {
        clsValue += entry.value;
      }
    }
    console.log('CLS:', clsValue);
  }).observe({ entryTypes: ['layout-shift'] });
};

// Resource loading performance
const analyzeResourceLoading = () => {
  const resources = performance.getEntriesByType('resource');
  
  resources.forEach(resource => {
    console.log({
      name: resource.name,
      duration: resource.duration,
      size: resource.transferSize,
      type: resource.initiatorType
    });
  });
};