JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsperformanceRuntime Performance & Profiling
Prev
performance
advanced
25 min read

Runtime Performance & Profiling

devtools
flame-chart
layout-thrashing
long-tasks
main-thread
profiling
requestAnimationFrame
runtime-performance
scheduler-yield
shared-array-buffer
web-workers

Runtime performance focuses on what happens after the page loads: identifying long tasks that block the main thread, avoiding layout thrashing, using requestAnimationFrame for smooth animations, and offloading heavy computation to Web Workers.

Key Points

1Long Tasks

Tasks exceeding 50ms block the main thread, preventing user input processing and frame painting. The Performance panel highlights these with red indicators.

2Layout Thrashing

Alternating DOM reads and writes in a loop forces synchronous layout recalculations. The fix is batching all reads before all writes.

3requestAnimationFrame

Schedules callbacks before the next paint, syncing with the display refresh rate. Automatically pauses in background tabs and batches with the rendering pipeline.

4Web Workers

Run JavaScript in a background thread parallel to the main thread. Cannot access DOM but enable heavy computation without blocking user interactions.

5DevTools Performance Panel

The flame chart, long task indicators, and frame timeline together reveal exactly which functions cause jank and where frame budgets are exceeded.

What You'll Learn

  • Use the Chrome DevTools Performance panel to record, analyze, and identify runtime bottlenecks
  • Detect and fix layout thrashing by batching DOM reads and writes
  • Implement smooth animations using requestAnimationFrame instead of setInterval
  • Offload expensive computations to Web Workers to keep the main thread responsive

Deep Dive

Runtime performance issues cause janky animations, unresponsive interactions, and sluggish scrolling — problems that frustrate users even on pages that load quickly. While loading performance is about getting content on screen fast, runtime performance is about keeping the experience smooth after the page is interactive.

The Main Thread Bottleneck

JavaScript runs on a single main thread that also handles layout, painting, and user input processing. When JavaScript executes a task longer than 50ms (a "long task"), the browser cannot respond to user input or paint new frames, causing visible jank. At 60fps, each frame has a budget of ~16ms. Exceeding this budget means dropped frames and stuttering.

Chrome DevTools Performance Panel

The Performance panel is the primary tool for diagnosing runtime issues. Record a session, then analyze:

Flame Chart: Shows the call stack over time. Wide bars indicate long-running functions. Look for JavaScript execution, layout, and paint operations that exceed the 16ms frame budget.

Long Tasks: The panel highlights tasks over 50ms with red corners. These are the tasks blocking the main thread. Click on them to see the full call stack and identify the culprit.

Frames: The frames section shows frame rate over time. Green bars mean frames rendered within budget (16ms). Red/yellow bars indicate dropped frames where the user experienced jank.

Bottom-Up and Call Tree: These tabs aggregate time by function, showing which functions consumed the most time across the entire recording. Sort by "Self Time" to find the actual bottlenecks rather than parent wrapper functions.

Layout Thrashing

Layout thrashing occurs when JavaScript alternates between reading layout properties and making DOM changes in a loop:

JavaScript
// BAD: Forces layout recalculation on every iteration
for (const el of elements) {
  el.style.width = container.offsetWidth + 'px'; // read, then write
}
 
// GOOD: Batch reads, then batch writes
const width = container.offsetWidth; // read once
for (const el of elements) {
  el.style.width = width + 'px'; // write only
}

Reading layout properties (offsetWidth, getBoundingClientRect(), scrollTop) after a DOM mutation forces the browser to recalculate layout synchronously — called a "forced reflow." In a loop, this multiplies the cost by the number of iterations. The fix is always to batch reads before writes.

requestAnimationFrame

requestAnimationFrame (rAF) schedules a callback to run just before the next paint, syncing your updates with the browser's refresh cycle:

JavaScript
function animate() {
  element.style.transform = `translateX(${position}px)`;
  position += velocity;
  if (position < target) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

Unlike setInterval(fn, 16), rAF automatically pauses when the tab is not visible (saving CPU), syncs with the actual display refresh rate (which may be 90Hz or 120Hz, not just 60Hz), and batches updates with the browser's rendering pipeline.

Web Workers

Web Workers run JavaScript in a background thread, completely parallel to the main thread. They cannot access the DOM but can perform heavy computations (image processing, data parsing, complex algorithms) without blocking user interactions:

JavaScript
// main.js
const worker = new Worker('processor.js');
worker.postMessage(largeDataSet);
worker.onmessage = (e) => updateUI(e.data);
 
// processor.js
self.onmessage = (e) => {
  const result = expensiveComputation(e.data);
  self.postMessage(result);
};

Communication happens via postMessage, which serializes data (structured clone). For large data transfers, use Transferable objects (ArrayBuffer, ImageBitmap) to move data without copying. SharedArrayBuffer enables shared memory between threads for maximum throughput.

scheduler.yield() and Task Scheduling

The emerging scheduler.yield() API allows long tasks to voluntarily yield control back to the browser, letting it process user input and paint frames between chunks of work. This is the modern replacement for the older setTimeout(fn, 0) yielding pattern and is specifically designed to improve INP scores.

Key Interview Distinction

Long tasks (>50ms) block the main thread. Layout thrashing forces synchronous reflows in loops. requestAnimationFrame syncs visual updates with the display refresh rate. Web Workers move computation off the main thread entirely. Each technique targets a different aspect of runtime performance.

Fun Fact

The 60fps standard comes from cinema: 24fps was the minimum for smooth motion perception, but digital displays adopted 60Hz for reduced flicker. Modern displays run at 90Hz, 120Hz, or even 240Hz — and requestAnimationFrame automatically adapts, while setInterval(fn, 16) would run too slowly on a 120Hz display.

Learn These First

Event Loop & Runtime

intermediate

Core Web Vitals & Performance Metrics

beginner

Continue Learning

Memory Leaks & Management

advanced

Debouncing & Throttling

intermediate

React Performance Optimization

intermediate

Practice What You Learned

How do you identify and fix JavaScript runtime performance issues?
senior
runtime
Use Chrome DevTools Performance tab to record and analyze flame charts, identify long tasks, and find layout thrashing. Common fixes include breaking up long tasks, avoiding forced synchronous layouts, using requestAnimationFrame, and moving work to Web Workers.
How do you identify and optimize long tasks on the main thread?
senior
runtime
Long tasks are JavaScript executions exceeding 50ms that block the main thread, causing unresponsive UI. Identify them with the Long Tasks API and PerformanceObserver, then optimize by breaking work into smaller chunks, yielding to the main thread, and offloading CPU-intensive work to Web Workers.
Previous
Rendering Strategies & Critical Rendering Path
Prev