Firefox DevTools has excellent performance profiling tools that are often overlooked. Here's a practical guide to measuring and diagnosing JavaScript performance issues.
The Performance Panel Overview
Open DevTools (F12) → Performance tab.
The profiler captures:
- JavaScript call stacks (where time is spent)
- Garbage collection events
- Frame rendering (for animation work)
- Network activity
- Worker activity
Unlike Chrome's performance tab, Firefox's profiler has a unique feature: flame chart vs tree view comparison and call tree inversion that makes it easier to find hot functions.
Basic Profiling Workflow
1. Start a recording
Click the record button (circle) or press Ctrl+Shift+P to start. Reproduce the slow behavior. Click stop.
Pro tip: Use a short recording (3-10 seconds) targeting the specific slow action. Long recordings generate too much data to analyze efficiently.
2. Reading the flame chart
The flame chart shows:
- X axis: time
- Y axis: call stack depth (bottom = entry point, top = leaf functions)
- Width of each bar: how long that function ran
Wide bars at the top are your hot spots — functions that ran for a long time.
3. The call tree
Switch to "Call Tree" view to see functions sorted by total time. "Self time" (time spent in the function itself, not callees) vs "Total time" (including callees) helps distinguish whether a function is genuinely slow or just calls something slow.
Invert the call tree: Shows leaf functions first. Useful for finding which specific operations are hot (e.g., a JSON.parse or DOM query taking disproportionate time).
Identifying Common Performance Issues
Heavy synchronous operations
Look for long continuous bars in the JavaScript thread row — these are "jank" that blocks the main thread. Common culprits:
- JSON parsing large payloads
- Synchronous regex on large strings
- Unoptimized array operations in loops
Excessive garbage collection
GC events appear as orange markers. Frequent GC indicates creating too many short-lived objects. Profile with the Memory tab to find allocation hotspots.
Layout thrashing
Alternating read/write DOM operations force the browser to recalculate layout repeatedly. In the flame chart, look for repeated "Layout" and "Recalculate Styles" calls.
Common pattern that causes layout thrashing:
// Bad: reads, then writes, then reads again in a loop
for (let i = 0; i < elements.length; i++) {
let height = elements[i].offsetHeight; // triggers layout
elements[i].style.height = height + 10 + 'px'; // write
}
// Better: batch reads, then writes
const heights = Array.from(elements).map(el => el.offsetHeight); // all reads
heights.forEach((h, i) => elements[i].style.height = h + 10 + 'px'); // all writes
The Firefox Profiler (Remote Tool)
Beyond DevTools, Firefox has the Firefox Profiler — a more powerful standalone analysis tool.
Capture profiles from DevTools and open them in the profiler for:
- Network lane comparison
- Marker timeline
- Source view with attribution
- Shareable profile URLs (for collaborating on performance issues)
To share: Profile → Export → Upload to profiler.firefox.com
Memory Profiling
Finding memory leaks
- DevTools → Memory tab
- Take a baseline snapshot (Snapshot 1)
- Perform the action you suspect leaks (e.g., navigate away and back)
- Take another snapshot (Snapshot 2)
- Switch to "Comparison" mode
The comparison shows what objects were created between snapshots. Look for object types growing unexpectedly (especially event listeners, DOM nodes, closures).
Allocation tracking
The "Allocations" feature records where objects are allocated. Enable in Performance settings. This shows you which lines of code are creating the most objects — useful for reducing GC pressure.
Network Performance in DevTools
The Network panel has a "Waterfall" column showing:
- DNS lookup time
- Connection time
- TLS handshake
- Time to first byte (TTFB)
- Content download time
Enable "Timings" column. Sort by duration to find slow requests. Filter by type (XHR, Fetch, CSS, JS) to focus.
Performance tip: The "Throttle" dropdown lets you simulate slower network conditions (3G, 4G). Profile your app under these conditions — things that feel fast on broadband may be unusable on mobile.
Rendering Performance
For animation and scrolling performance:
- Enable FPS (frames per second) counter: DevTools → Settings → FPS Meter
- Record in Performance tab while scrolling or animating
- Look for dropped frames (red bars in the frame rate section)
A smooth 60fps means each frame must complete in ≤16ms. Any frame taking longer causes visible stuttering.
about:performance — The Built-in Performance Monitor
Open a new tab and navigate to about:performance for a live view of:
- Memory usage per tab and extension
- Energy impact (useful for finding tabs that drain battery)
Good for identifying if a specific extension or tab is causing browser-wide slowness — use this before diving into DevTools profiling.
Practical Tips
Start with the simplest tool: console.time() / console.timeEnd() for quick measurements before opening the profiler.
Profile production builds: Dev builds with source maps and hot reloading are much slower. Performance issues in dev may not exist in prod and vice versa.
Disable extensions while profiling: Extensions run in the same process and can affect measurements.
Use the profiler markers API: Instrument your code with performance.mark() and performance.measure() to add visible markers to the flame chart.
performance.mark('data-load-start');
const data = await fetchData();
performance.mark('data-load-end');
performance.measure('Data Loading', 'data-load-start', 'data-load-end');
These show up as named markers in the profiler, making it easy to correlate performance data with your application's logical operations.
Top comments (0)