π¦ JavaScript Deep Dive β Issue #3
Modern JavaScript Performance Patterns (2025 Edition)
How to Write Faster, Smoother, More Efficient JS in a Modern Front-End World
JavaScript performance isnβt just about shaving a few milliseconds.
It affects:
- π§ Perceived responsiveness
- π± Battery life on mobile devices
- π¨ Smoothness of UI animations
- β‘ Load times and interactivity
- π Core Web Vitals scores
And with modern apps becoming more interactive β and LLM-driven apps doing async work at scale β understanding performance patterns is now a must-have skill for every serious JavaScript developer.
This issue shows you what really slows down JS, and the modern patterns that high-performance teams use in 2025 (React, Svelte, Vue, Vanilla, Node, and everything in between).
π¨ 1. Understanding Rendering Costs
Every time you modify the DOM, the browser may need to:
- Recalculate styles
- Perform layout (expensive!)
- Repaint
- Composite layers
This pipeline is known as reflow + repaint, and itβs a major performance bottleneck.
β Bad: Causing layout thrashing
for (let i = 0; i < 100; i++) {
el.style.width = el.offsetWidth + 1 + 'px';
}
This forces the browser to recalc layout 100 times.
β Good: Batch your reads + writes
const width = el.offsetWidth; // read once
el.style.width = width + 100 + "px"; // write once
Modern Best Practice (2025):
Use a scheduler like:
requestAnimationFramefor visual updatesrequestIdleCallbackfor non-critical work- Custom batching (React, Svelte, Solid, Vue all do this internally)
π¨ 2. Avoid Long Tasks (Anything > 50ms)
A βlong taskβ blocks the main thread and hurts INP/LCP, UI responsiveness, and touch input.
β Bad
// Freezes UI
while (expensiveOperation()) {}
β Good: Chunk work
function processChunk(items) {
if (items.length === 0) return;
const chunk = items.splice(0, 100);
// Process in batches
chunk.forEach(doWork);
requestIdleCallback(() => processChunk(items));
}
processChunk(largeArray);
Why this works
The browser gets breathing room between chunks β smoother UI.
π¨ 3. Use Web Workers for CPU-Heavy Work
JavaScript on the main thread should stay lightweight.
Heavy CPU work belongs in a Worker, where it wonβt block rendering.
Example
// main.js
const worker = new Worker('worker.js');
worker.postMessage(largeData);
worker.onmessage = (e) => {
console.log("Processed:", e.data);
};
// worker.js
onmessage = (e) => {
const result = crunchNumbers(e.data);
postMessage(result);
};
Use Workers for:
- Image processing
- Data parsing
- AI model inference / embedding
- Crypto / hashing
- Sorting huge arrays
π¨ 4. Optimize Memory (Closures, Arrays & Hidden Costs)
Closures can unintentionally retain memory
function create() {
const bigArray = new Array(1_000_000);
return function() {
console.log(bigArray.length);
};
}
You think the array is temporary β but it’s retained forever.
Avoid memory leaks by:
β Nulling references
β Avoiding unnecessary closures
β Removing event listeners
β Using WeakMap / WeakRef for caching
π¨ 5. Understanding Hidden Classes & Inline Caches (V8 Optimization)
JavaScript engines optimize objects internally.
But certain patterns cause de-optimizations.
β Avoid changing object shapes
obj.a = 1;
obj.b = 2;
delete obj.a; // slow!
β Avoid mixed types
arr[0] = 1;
arr[1] = "hello"; // deoptimized
β Avoid sparse arrays
const arr = [1, , 3]; // holey array = slower operations
β Keep arrays dense and typed
const arr = [1, 2, 3]; // optimized
π¨ 6. Async Performance: “Fast” isnβt always fast
Promises and async/await provide clean code β but they can generate clogged microtask queues.
β Bad
for (let i = 0; i < 100000; i++) {
await doSomething();
}
This creates 100,000 microtasks, blocking rendering.
β Good
Run tasks in parallel when possible:
await Promise.all(items.map(doSomething));
Or schedule in batches:
function batch(items) {
const chunk = items.splice(0, 100);
return Promise.all(chunk.map(doSomething));
}
async function run() {
while (items.length) await batch(items);
}
π¨ 7. Use Modern Browser APIs for Performance Wins
β IntersectionObserver
Load images or heavy components only when visible.
β ResizeObserver
Avoid expensive polling loops.
β AbortController
Cancel async operations you no longer need.
β structuredClone
Copy large objects 10β100x faster than JSON.
π§© Mini Exercises for Readers
1. Why is this slow?
for (let i = 0; i < 10000; i++) {
list.innerHTML += "<li>Item</li>";
}
2. Optimize this code:
async function run() {
for (let item of items) {
await fetchData(item);
}
}
3. Explain why this array is slow:
const arr = [];
arr[999] = 1;
π¦ Performance Best Practices Checklist (2025 Edition)
β Batch DOM updates
β Offload heavy work to Web Workers
β Avoid long tasks (>50ms)
β Keep arrays dense
β Keep object shapes consistent
β Use rAF + rIC scheduling
β Lazy load everything possible
β Use parallel async execution
β Avoid large microtask queues
β Leverage Observers & AbortController
π Final Thoughts
Performance is no longer just a βnice to have.β
Itβs a competitive advantage β for SEO, user experience, and app quality.
Modern JavaScript isn’t just about writing code that works.
It’s about writing code that works fast, runs smoothly, and scales effortlessly.
Next issue:
π Issue #4 β Functional Programming Superpowers in JavaScript