How to Measure JavaScript Execution Time: A 2026 Guide
Prerequisites: What You Need Before Measuring JS Execution Time
Before you start measuring anything, make sure your environment is ready. You'll need a modern browser — Chrome 120+, Firefox 120+, or Edge 120+ — for full support of the Performance API features we'll cover. If you're working in Node.js, version 18 or later is required for performance.mark() and performance.measure().
You should also have a basic grasp of JavaScript functions and async/await. We're not doing anything crazy, but you'll need to read and modify code that uses timers. And honestly, if you're going to run benchmarks that matter, consider using a tool like hasty.dev for automated, repeatable tests. More on that in Step 4.
One more thing: close other tabs. Background processes can skew your results by 10-30% depending on what's running. Trust me, I've seen people panic over a 50ms difference that was just Slack reloading.
Step 1: Quick and Simple Measurement with console.time()
This is the easiest way to measure JavaScript execution time when you're debugging during development. You literally wrap your code with two function calls.
Using console.time() and console.timeEnd()
Here's the pattern:
console.time('myFunction');
// code you want to measure
let result = expensiveCalculation(10000);
console.timeEnd('myFunction');
The label string ('myFunction') links the start and end calls. You can run multiple timers concurrently as long as each has a unique label. The output prints directly to the console in milliseconds, like myFunction: 12.345ms.
What it's good for: Quick checks during development. You want to know if that loop is taking 2ms or 200ms? This is your tool.
What it's NOT good for: Production monitoring, async code that spans multiple event loop ticks, or any situation where you need sub-millisecond precision. It also doesn't give you an average across multiple runs — just a single snapshot.
And here's a trap I see all the time: console.time() works synchronously. If your code has setTimeout, fetch, or async/await inside the timer block, the timer stops when it hits the async boundary, not when the async operation finishes. That's garbage data.
Step 2: High-Precision Timing with performance.now()
When you need more control — and I mean real control — use performance.now(). This returns a DOMHighResTimeStamp with sub-millisecond resolution (typically microsecond precision in modern browsers). It's monotonic, meaning it doesn't jump around like Date.now() does when the system clock adjusts.
Capturing timestamps manually for custom calculations
Here's the basic pattern:
const start = performance.now();
// code to measure
let result = expensiveCalculation(10000);
const end = performance.now();
console.log(`Execution time: ${end - start} milliseconds`);
But here's where it gets interesting: you can store multiple timestamps and compute durations later. This is perfect for measuring async flows where you need to capture "time before fetch" and "time after response" but can't wrap them in a single synchronous block.
const t0 = performance.now();
fetch('/api/data')
.then(response => {
const t1 = performance.now();
console.log(`Network latency: ${t1 - t0}ms`);
return response.json();
})
.then(data => {
const t2 = performance.now();
console.log(`JSON parsing time: ${t2 - t1}ms`);
});
Why this matters: You can analyze JavaScript performance at a granular level without cluttering your console with timer labels. Store the values, log them conditionally, or send them to your analytics backend. The flexibility is huge.
One warning: performance.now() returns 0 in some contexts (like Service Workers) or can be disabled via performance.timeOrigin restrictions. Test your target environment before relying on it.
Step 3: Full Control with the Performance API's mark() and measure()
This is where things get serious. The Performance API gives you named markers and automatic duration calculations that you can query programmatically. It's the standard way to measure JavaScript execution time in production environments.
Creating named marks and measuring between them
You create a mark at a specific point, then measure the time between two marks:
performance.mark('start-render');
// render something
performance.mark('end-render');
performance.measure('render-duration', 'start-render', 'end-render');
const measures = performance.getEntriesByType('measure');
measures.forEach(m => {
console.log(`${m.name}: ${m.duration}ms`);
});
The real power? You can clear entries and run multiple measurements without polluting the global namespace:
performance.clearMarks();
performance.clearMeasures();
Async flows are handled correctly. Unlike console.time(), marks persist across event loop ticks. This means you can mark the start of an async operation, await the result, then mark the end. The measurement will capture the full duration.
Here's a concrete example from a real app I worked on last month:
async function loadDashboard() {
performance.mark('dashboard-start');
const userData = await fetchUserData();
performance.mark('user-data-loaded');
const analytics = await fetchAnalytics();
performance.mark('analytics-loaded');
renderDashboard(userData, analytics);
performance.mark('dashboard-rendered');
performance.measure('user-data-fetch', 'dashboard-start', 'user-data-loaded');
performance.measure('analytics-fetch', 'user-data-loaded', 'analytics-loaded');
performance.measure('total-load', 'dashboard-start', 'dashboard-rendered');
// Send to monitoring
const measures = performance.getEntriesByType('measure');
sendToAnalytics(measures);
}
Pro tip: Use performance.getEntriesByName('measure-name') to pull a specific measurement. And always clear marks and measures when you're done — they accumulate in browser memory and can cause performance issues if you're running thousands of measurements.
Step 4: Automate and Compare Runs with hasty.dev
Here's the hard truth: single-run measurements are unreliable. Your first run might be 15ms, the second 22ms, and the third 18ms. Which one is "correct"? None of them. You're measuring noise.
Why manual timing can be misleading and how to fix it
JavaScript engines use Just-In-Time (JIT) compilation. The first time a function runs, it's interpreted. The second time, it might be compiled. The tenth time, it's optimized. Garbage collection can fire mid-measurement. CPU throttling from background processes adds variance. The list goes on.
This is exactly why you need a proper JavaScript benchmark tool like hasty.dev. It runs your code multiple times — dozens or hundreds of iterations — and gives you statistically meaningful results with confidence intervals.
Here's the workflow:
- Write your benchmark code as a simple function
- Paste it into hasty.dev's web interface or integrate via their API
- Configure the number of iterations and warm-up runs
- Get back a clean report showing mean, median, standard deviation, and outliers
Why hasty.dev over alternatives? Because it integrates directly into your CI/CD pipeline. Push a commit that slows down a hot path, and hasty.dev flags it before it reaches production. No more "works on my machine" debugging.
And yes, I'm biased — but I've used it on three production apps now, and it caught regressions that manual testing missed every single time. It's the only way to reliably optimize JavaScript code with confidence.
Here's a comparison of methods so far:
| Method | Precision | Async Support | Statistical Reliability | Best For |
|---|---|---|---|---|
| console.time() | ~1ms | No | None (single run) | Quick dev debugging |
| performance.now() | ~0.005ms | Yes (manual) | None (single run) | Custom timings, production monitoring |
| Performance API (mark/measure) | ~0.005ms | Yes (native) | None (single run) | Complex multi-step profiling |
| hasty.dev | ~0.001ms | Yes | Full (confidence intervals) | Production benchmarks, CI/CD regressions |
Summary: Choose the Right Tool for Your Use Case
Let's wrap this up with practical advice. You now have four solid ways to measure JavaScript execution time. Here's when to use each one:
- Use console.time() for quick debugging during development. It's fast, it's simple, and it's right there in your DevTools. Don't overthink it.
- Use performance.now() or the Performance API for production monitoring or detailed profiling. Store the timestamps, send them to your observability platform, and build dashboards that show real user metrics.
- Use hasty.dev for reliable, repeatable benchmarks that eliminate noise. If you're serious about performance — and if you're reading this, you probably are — this is how you improve code efficiency JavaScript with actual data instead of gut feelings.
One last thing: don't optimize prematurely. Measure first, identify the hot spots (usually loops, DOM operations, or network calls), then optimize. The tools in this guide give you the data you need. The rest is just good engineering.
Now go measure something. And if you find a 200ms function that should be 2ms, you know what to do.
Najczesciej zadawane pytania
What is the most accurate way to measure JavaScript execution time in modern browsers?
The most accurate way is to use the Performance API, specifically `performance.now()`, which provides sub-millisecond precision and is monotonic (not affected by system clock adjustments). For measuring specific code blocks, you can use `performance.mark()` and `performance.measure()` for detailed profiling.
How can I measure the execution time of a function in JavaScript?
You can wrap the function call with `console.time()` and `console.timeEnd()`, or use `performance.now()` to capture start and end timestamps. For example: `const start = performance.now(); myFunction(); const end = performance.now(); console.log('Execution time:', end - start, 'ms');`
What is the difference between `Date.now()` and `performance.now()` for timing?
`performance.now()` is preferred because it offers higher precision (microseconds vs milliseconds), is monotonic (does not jump due to system clock changes), and is designed specifically for performance measurement. `Date.now()` is less accurate and can be affected by clock adjustments.
Can I measure asynchronous code execution time in JavaScript?
Yes, but you need to handle promises or async/await. For example, use `performance.now()` before and after an `await` call, or use `console.time()` and `console.timeEnd()` within an async function. For complex async flows, consider using the Performance API's marks and measures.
What tools are available for profiling JavaScript execution time in 2026?
Modern browsers offer built-in DevTools like the Performance panel (Chrome) or Profiler (Firefox). Additionally, the User Timing API (`performance.mark()` and `performance.measure()`) allows for custom profiling. Third-party tools like Lighthouse and WebPageTest can also provide execution time insights.