Using Chrome DevTools for JS Performance Tuning
Find and fix slow JavaScript with Chrome DevTools. Learn to record performance profiles, read flame charts, use CPU throttling, and identify bottlenecks that make your app feel sluggish.
Chrome DevTools has a full performance analysis suite built into every Chrome browser. You can record exactly what your JavaScript does during a user interaction, see a visual timeline of every function call, and find the specific lines that take the most time. This guide covers the Performance panel, CPU throttling, the flame chart, and the Sources debugger for performance work.
Recording a performance profile
Open DevTools (F12 or right-click anywhere and choose Inspect) and click the Performance tab. The workflow is:
- Click the circle record button (or press Ctrl+E).
- Perform the action you want to analyze: click a button, scroll, type in a field.
- Click Stop (or press Ctrl+E again).
You now have a profile showing everything that happened: JavaScript execution, layout recalculations, style updates, painting, and rendering.
Record for 3 to 5 seconds. Longer recordings generate too much data to analyze easily. Focus on one interaction at a time.
Reading the flame chart
The flame chart is the main visualization in the Performance panel. Each horizontal bar represents a function call, and reading it comes down to three rules.
Width equals time, so a wide bar means the function took a long time to complete. Stacking shows the call hierarchy: if function A calls function B, B's bar sits on top of A's bar, and the full height shows the call stack depth. Tall stacks with wide bars are the best targets, since a stack that is both deep and wide is where the most time is being spent.
The x-axis is time. The y-axis is the call stack. Bars are color-coded:
| Color | Meaning |
|---|---|
| Yellow | JavaScript execution |
| Purple | Style recalculation and layout |
| Green | Paint and compositing |
| Gray | Browser internal work |
If most of the flame chart is yellow, JavaScript is the bottleneck. If it is purple, you are triggering too many layout recalculations.
Click any bar to jump to the Sources panel showing the exact function code. The Bottom-Up tab below the flame chart lists every function sorted by total time. This is often the fastest way to find the expensive function.
CPU throttling
Your development machine is probably faster than what most users have. Chrome can simulate a slower CPU to reveal problems that are invisible at full speed:
- In the Performance panel, find the CPU dropdown next to the record button.
- Select 4x slowdown or 6x slowdown.
- Record your interaction again and compare.
A function that takes 5ms on a fast machine takes 30ms at 6x slowdown. If the throttled profile shows frames taking longer than 16ms (the budget for 60fps), your users on mid-range devices are experiencing jank.
The Sources panel for line-by-line analysis
When you have identified a slow function in the flame chart, open the Sources panel. The debugger runs inside this panel:
- Breakpoints: Click a line number to set a breakpoint. The next time that line executes, the debugger pauses and you can inspect variables, the call stack, and step through line by line.
- Conditional breakpoints: Right-click a line number and choose "Add conditional breakpoint." Enter a condition like
i > 100to pause only on the 101st iteration of a loop. - Logpoints: Right-click and choose "Add logpoint." Instead of pausing, it logs a message to the console. This is useful for tracking values in hot loops without stopping.
function findSlowRendering(items) {
// Set a breakpoint on this line to inspect `items.length`
for (let i = 0; i < items.length; i++) {
// Add a logpoint here: "Processing item", i, items[i].name
renderItem(items[i]);
}
}Finding the real bottleneck
Here is a systematic approach to finding what to optimize:
- Identify slow frames. In the Performance panel, look at the FPS chart at the top. Drops below 60fps indicate jank, so click those regions to zoom in.
- Switch to the Bottom-Up tab. This sorts every function by total self time. The function at the top is your primary suspect, and it may not be the function you expect.
- Check the Call Tree tab. This shows the inclusive time, meaning the function plus everything it calls. A high inclusive time with a low self time means the real work is happening in its children.
- Verify with performance.now(). Before optimizing, wrap the suspect code in timing calls so you can measure the exact before-and-after improvement:
const start = performance.now();
suspectFunction();
const end = performance.now();
console.log(`Before fix: ${end - start}ms`);Common performance problems and what they look like
Forced synchronous layouts. You read a layout property (like offsetHeight) right after changing the DOM, forcing the browser to recalculate layout before the next frame. In the flame chart, you see alternating purple (layout) and yellow (JS) bars in a tight pattern inside one frame.
Expensive event handlers. A scroll or mousemove handler that does heavy work on every event. The flame chart shows the same yellow bar firing at 60+ times per second. Fix with debouncing or throttling.
Long garbage collection pauses. The flame chart shows sawtooth patterns: memory climbs, then a wide gray bar appears while the garbage collector runs. Fix by reducing object allocation inside hot loops.
Large recalculate style blocks. Wide purple bars after JavaScript runs. This means your code changed classes or inline styles on many elements at once. Batch DOM reads and writes separately, or use requestAnimationFrame.
Taking a heap snapshot for memory
The Memory panel (separate tab in DevTools) captures JavaScript heap snapshots. This is useful when performance profiling shows garbage collection pauses:
- Click the Memory tab.
- Select Heap snapshot and click Take snapshot.
- Perform the action you are investigating.
- Take a second snapshot.
- Use the Comparison view to see what objects were allocated between snapshots.
Look for large object counts, detached DOM elements (nodes removed from the page but still held in JS variables), and unexpected retained arrays.
For more on measuring execution time programmatically, see how to measure JavaScript execution time accurately. For debugging the errors that show up during profiling, see the try...catch guide.
Rune AI
Key Insights
- Use the Performance panel to record a few seconds of interaction and see a flame chart of all function calls.
- Wider bars in the flame chart mean longer execution time; start optimization there.
- Enable CPU throttling (4x or 6x slowdown) to simulate performance on low-end devices.
- The Bottom-Up and Call Tree tabs sort functions by total time, making bottlenecks obvious.
- Set breakpoints in the Sources panel to pause execution and inspect variables at specific points.
- Always measure before and after optimizing to confirm the fix actually helped.
Frequently Asked Questions
How do I open the Performance panel in Chrome DevTools?
What is a flame chart and how do I read it?
What does CPU throttling do and why should I use it?
Conclusion
Chrome DevTools turns guesswork into data. The Performance panel shows you exactly which functions take the most time, the Sources debugger lets you step through hot paths line by line, and CPU throttling reveals how your code behaves on slower devices. The workflow is simple: record, read the flame chart, find the widest bars, and optimize what matters most.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.