Skip to main content

Bottlenecks in JS code

1. Main Thread Blocking

JS is single-threaded. Any heavy operation blocks the UI, rendering, and event handling.

Examples:

  • large loops (for, while, forEach) without setTimeout/requestIdleCallback;
  • parsing or processing large JSON (JSON.parse(hugeData));
  • computationally heavy algorithms (sorting, recursion, encryption);
  • synchronous requests (XMLHttpRequest without async);
  • large DOM changes within a single frame.

How to fix it:

  • split the work into chunks (setTimeout, requestAnimationFrame);
  • use Web Workers for background computation;
  • apply debounce / throttle for events.

2. Excessive re-renders and DOM manipulation

DOM operations are the most expensive in terms of performance.

Problems:

  • too many element insertions/removals;
  • recalculating styles and layout on every change;
  • accessing offsetHeight, getComputedStyle, scrollTop → triggers reflow;
  • loops that modify the DOM.

How to fix it:

  • use DocumentFragment, a virtual DOM, batch updates;
  • cache element references;
  • minimize reflow - change a class for a whole group of elements at once;
  • in React: memoization, PureComponent, React.memo, useMemo, useCallback.

3. Excessive memory consumption (memory leaks)

Memory leaks cause the tab to get "heavier" over time, and the UI freezes.

Causes:

  • uncleared timers (setInterval, setTimeout);
  • "dangling" event listeners (not removed when the element is removed);
  • closures that keep references to large objects;
  • global variables (never cleared);
  • caches that are never cleared.

Solutions:

  • clear timers (clearInterval, clearTimeout);
  • remove handlers (removeEventListener);
  • use WeakMap / WeakSet;
  • analyze with Chrome DevTools → Memory.

4. Inefficient loops and collections

Especially with large arrays.

Typical mistakes:

  • nested O(n²) loops with no real need;
  • using .map() / .filter() / .reduce() on large arrays without optimization;
  • creating new arrays/objects on every iteration;
  • frequent calls to Array.splice() / Array.shift() (expensive operations).

What to do:

  • use more suitable structures: Set, Map, WeakMap;
  • use iterators, generators, for...of instead of forEach for large volumes;
  • profile sections with performance.now().

5. Excessive network requests

Even fast JS code will not save you if the network is congested.

Problems:

  • repeated requests without caching;
  • duplicate API calls on every render;
  • loading huge JS/CSS bundles;
  • no gzip / brotli compression;
  • no lazy loading.

How to fix it:

  • caching (HTTP cache, IndexedDB, SW, memoization);
  • batching requests;
  • React Query, SWR, Cache-Control;
  • code splitting and dynamic import (import()).

6. Poor rendering optimization (rendering bottlenecks)

The UI "jitters", animations lag, FPS drops.

Causes:

  • too frequent changes to style/transform;
  • using heavy shadows, filters, border-radius;
  • not using the GPU (CSS animations without transform: translateZ(0));
  • recalculating layout on every animation frame.

Solutions:

  • offload animations to the GPU;
  • batch DOM changes into a single frame;
  • use will-change, transform, opacity;
  • requestAnimationFrame instead of timers for animations.

7. A heavy bundle (bundle size)

The more JS there is, the longer it takes to load and parse.

Causes:

  • pulling in unnecessary libraries;
  • duplicated dependencies;
  • not using tree-shaking;
  • inline JSON, large icons, images embedded in the code.

Solutions:

  • analyze the bundle (webpack-bundle-analyzer, next build --analyze);
  • tree-shaking, code splitting, dynamic import();
  • use a CDN, HTTP/2, ESM bundles;
  • minification (Terser, SWC).

8. Suboptimal data structures and algorithms

Example: sorting an array of 100,000 elements with sort() without a comparator, or searching with filter() instead of a Set.

What to do:

  • choose the structure for the task: Set for uniqueness, Map for fast lookups;
  • avoid a linear search when a hash-based lookup can be used;
  • use binary search, cache computed values.

9. Lack of profiling and metrics

The most common mistake is "optimizing at random".

Solutions:

  • Chrome DevTools (Performance, Memory, Coverage);
  • console.time(), performance.mark() / measure();
  • Lighthouse / Web Vitals;
  • Sentry Performance, New Relic, Datadog.

Quick summary

CategoryExample problemHow to fix it
Thread blockingA long loopSplit it up, use a Worker
DOMLots of reflowBatch updates
MemoryLeaksWeakMap, cleanup
LoopsO(n²)Optimize
NetworkRepeated requestsCache them
RenderingFPS < 60GPU animations
Bundle2 MB of JSTree-shaking
AlgorithmsWrong structureChoose based on the task

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.