Performance Optimization Techniques

Performance optimization is crucial for providing a good user experience. Understanding various optimization techniques helps build faster and more efficient applications.

Code Optimization

// Memoization
const memoize = (fn) => {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
};

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

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

Loading Optimization

// Lazy loading components
const LazyComponent = React.lazy(() => 
  import('./HeavyComponent')
);

// Dynamic imports
async function loadModule() {
  const module = await import('./large-module.js');
  module.doSomething();
}

// Image loading
<img 
  loading="lazy"
  srcset="small.jpg 300w, medium.jpg 600w"
  sizes="(max-width: 600px) 300px, 600px"
  src="fallback.jpg"
  alt="Optimized image"
/>

React Performance

// Using memo
const MemoizedComponent = React.memo(function MyComponent(props) {
  return <div>{props.data}</div>;
});

// useMemo for expensive calculations
const memoizedValue = useMemo(() => 
  computeExpensiveValue(a, b), 
  [a, b]
);

// useCallback for callbacks
const memoizedCallback = useCallback(
  () => doSomething(a, b),
  [a, b]
);

// Virtual list for large datasets
function VirtualList({ items }) {
  return (
    <VirtualScroll
      itemCount={items.length}
      itemSize={50}
      renderItem={({ index, style }) => (
        <div style={style}>{items[index]}</div>
      )}
    />
  );
}

Network Optimization

// Caching responses
const cache = new Cache();

async function fetchWithCache(url) {
  const cached = await cache.match(url);
  if (cached) return cached;
  
  const response = await fetch(url);
  cache.put(url, response.clone());
  return response;
}

// Request batching
class RequestBatcher {
  queue = [];
  timeout = null;
  
  add(request) {
    this.queue.push(request);
    if (!this.timeout) {
      this.timeout = setTimeout(() => this.flush(), 100);
    }
  }
  
  async flush() {
    const requests = this.queue;
    this.queue = [];
    this.timeout = null;
    return batchRequest(requests);
  }
}

Common Interview Follow-up Questions

  1. How do you identify performance bottlenecks?
  2. What tools do you use for performance monitoring?
  3. How do you optimize React component rendering?
  4. What are the best practices for code splitting?

Best Practices

  • Measure before optimizing
  • Use appropriate caching strategies
  • Implement code splitting
  • Optimize images and assets
  • Minimize network requests
  • Use performance monitoring tools