Question
I need to measure how long a function takes to execute in milliseconds.
Originally, this was commonly done with new Date().getTime(), but today the more appropriate standard approach is to use the performance.now() API.
What is the correct way to measure execution time in JavaScript, and when should performance.now() be preferred over older date-based approaches?
Short Answer
By the end of this page, you will understand how to measure execution time in JavaScript, why performance.now() is usually the best choice for benchmarking code, how to use it correctly, and what mistakes to avoid when timing functions.
Concept
Measuring execution time means recording a timestamp before some code runs, recording another timestamp after it finishes, and subtracting the two values.
In JavaScript, the modern tool for this is performance.now().
const start = performance.now();
// code to measure
const end = performance.now();
console.log(`Time taken: ${end - start} ms`);
Why performance.now() matters
performance.now() is designed for performance measurements:
- It returns a time value in milliseconds.
- It has better precision than older date-based methods.
- It is intended for measuring short durations like function execution.
- It is not affected in the same way as wall-clock time APIs used for dates and times.
Older approaches like new Date().getTime() or Date.now() return the current calendar time in milliseconds since the Unix epoch. They are useful for timestamps, but less ideal for precise benchmarking.
What you are really measuring
When you time a function, you are measuring:
- JavaScript execution time
- Possible engine optimizations or warm-up effects
- Time spent in loops, calculations, and synchronous operations
If your function does asynchronous work, such as fetch, setTimeout, or database calls, you need a different timing pattern because the function may return before the work is finished.
Mental Model
Think of timing code like using a stopwatch.
- Press start right before the function runs.
- Press stop right after it finishes.
- The difference is the duration.
performance.now() is like a stopwatch built specifically for measuring elapsed time.
Date.now() is more like looking at a wall clock. It tells you the current time, which is useful, but it is not the best tool when you care about small, precise durations.
Syntax and Examples
Basic syntax
const start = performance.now();
doSomething();
const end = performance.now();
console.log(`Execution time: ${end - start} ms`);
Example: measuring a synchronous function
function calculateSum() {
let total = 0;
for (let i = 0; i < 1000000; i++) {
total += i;
}
return total;
}
const start = performance.now();
const result = calculateSum();
const end = performance.now();
console.log("Result:", result);
console.log(`Execution time: ${(end - start).toFixed(3)} ms`);
In this example:
startstores the time before the function runs.calculateSum()executes.endstores the time after execution.end - startgives the elapsed time.
Older alternative: Date.now()
const start = Date.now();
doSomething();
const end = Date.now();
console.log(`Execution time: ${end - start} ms`);
This works, but performance.now() is usually better for measuring code performance.
Measuring an async function
async function loadData() {
return new Promise(resolve => {
setTimeout(() => resolve("done"), 300);
});
}
async function measure() {
const start = performance.now();
const result = await loadData();
const end = performance.now();
console.log(result);
console.log(`Execution time: ${(end - start).toFixed(3)} ms`);
}
measure();
For asynchronous code, place the end measurement after await so the full operation is included.
Step by Step Execution
Consider this example:
function greetManyTimes() {
let text = "";
for (let i = 0; i < 3; i++) {
text += "Hello ";
}
return text.trim();
}
const start = performance.now();
const message = greetManyTimes();
const end = performance.now();
console.log(message);
console.log(end - start);
Step by step
greetManyTimesis defined.startstores the current high-resolution timestamp.greetManyTimes()runs.- Inside the function:
textstarts as an empty string.- The loop runs 3 times.
- Each time,
"Hello "is added. - The function returns
"Hello Hello Hello".
messagereceives the returned string.endstores the timestamp after the function has finished.end - startis calculated.- The result is the elapsed time in milliseconds.
Example trace
If:
start = 1250.100end = 1250.450
Then:
elapsed = 1250.450 - 1250.100 = 0.350 ms
That means the function took about 0.35 milliseconds.
Real World Use Cases
Measuring execution time is useful in many real programs.
Performance checks
You may want to compare two implementations:
- a
forloop vsArray.map() - two sorting strategies
- a cached function vs a non-cached one
API and async timing
You might measure how long an API request takes:
async function fetchUsers() {
const start = performance.now();
const response = await fetch('/api/users');
const data = await response.json();
const end = performance.now();
console.log(`Request took ${(end - start).toFixed(2)} ms`);
return data;
}
UI performance
In frontend apps, developers measure:
- render time
- event handler duration
- animation performance
- expensive calculations triggered by user input
Backend scripts and tools
In Node.js scripts, timing helps with:
- file processing
- data transformation
- report generation
- batch jobs
Real Codebase Usage
In real projects, developers usually do more than just print a number.
Common patterns
1. Wrap timing in a helper
function measure(label, fn) {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(3)} ms`);
return result;
}
const value = measure("sum calculation", () => {
let total = 0;
for (let i = 0; i < 1000000; i++) total += i;
return total;
});
This keeps timing code reusable.
2. Use try...finally when timing important code
function measureSafe(fn) {
const start = performance.now();
try {
return fn();
} finally {
const end = performance.now();
console.log(`Finished in ${(end - start).toFixed(3)} ms`);
}
}
This ensures timing is logged even if an error happens.
3. Time async helpers
async function measureAsync(label, fn) {
const start = performance.now();
try {
return await fn();
} finally {
const end = performance.now();
console.log(`${label}: ${(end - start).toFixed(3)} ms`);
}
}
4. Benchmark multiple runs
A single run can be misleading. Developers often run code many times and average the result.
function benchmark(fn, iterations = 1000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
return (end - start) / iterations;
}
This helps reduce noise.
Common Mistakes
1. Using Date for precise benchmarking
Broken approach:
const start = new Date().getTime();
doSomething();
const end = new Date().getTime();
This may work, but it is not the preferred modern choice for measuring short durations.
Use instead:
const start = performance.now();
doSomething();
const end = performance.now();
2. Timing async code incorrectly
Broken example:
const start = performance.now();
fetch('/api/data');
const end = performance.now();
console.log(end - start);
This only measures how long it took to start the request, not complete it.
Correct version:
const start = performance.now();
await fetch('/api/data');
const end = performance.now();
3. Measuring code only once
One execution can be affected by:
- engine warm-up
- background processes
- caching
- system load
Better approach: run the code several times and compare averages.
4. Including unrelated work in the measurement
Broken example:
const start = performance.now();
const result = heavyCalculation();
console.log(result);
const end = performance.now();
This includes console.log, which can affect the timing.
Better:
const start = performance.now();
const result = heavyCalculation();
const end = performance.now();
console.log(result);
console.log(end - start);
5. Comparing tiny operations directly
Very small operations can complete too quickly to compare reliably in one run. Repeat them many times before drawing conclusions.
Comparisons
| Approach | Best use | Precision | Good for benchmarking? | Notes |
|---|---|---|---|---|
performance.now() | Measuring elapsed execution time | High | Yes | Preferred modern API |
Date.now() | Current timestamp | Lower | Sometimes | Fine for coarse timing |
new Date().getTime() | Current timestamp | Lower | Sometimes | Older style, same idea as Date.now() |
console.time() / console.timeEnd() | Quick debugging in development | Varies by environment | Sometimes | Convenient but less flexible |
performance.now() vs Date.now()
- Use
performance.now()when you care about measuring code duration. - Use
Date.now()when you want the current timestamp for logs, records, or comparisons with real-world time.
performance.now() vs console.time()
console.time() is handy for quick experiments:
console.time("task");
doSomething();
console.timeEnd("task");
This is convenient, but performance.now() gives you more control because you can store, calculate, return, and aggregate the timing values yourself.
Cheat Sheet
Quick reference
Preferred timing API
const start = performance.now();
// code here
const end = performance.now();
const duration = end - start;
Older alternatives
Date.now();
new Date().getTime();
Use these for timestamps, not ideal for precise benchmarks.
Async timing
const start = performance.now();
await someAsyncTask();
const end = performance.now();
Quick debug timing
console.time("myTask");
doSomething();
console.timeEnd("myTask");
Good habits
- Use
performance.now()for elapsed time - Measure only the code you care about
- Repeat benchmarks multiple times
- Keep logging outside the timed section when possible
- Use
awaitfor async work before stopping the timer
Watch out for
- timing async code without
await - comparing tiny operations from a single run
- including setup or output code accidentally
FAQ
Should I use performance.now() or Date.now() in JavaScript?
Use performance.now() for measuring execution time. Use Date.now() for real timestamps such as logging when something happened.
Is new Date().getTime() still valid?
Yes, it still works, but it is an older style. For performance measurement, performance.now() is the better modern choice.
Does performance.now() return milliseconds?
Yes. It returns a time value in milliseconds, typically with fractional precision.
How do I measure an async function's execution time?
Record the start time before the async call and the end time after await completes.
Why do benchmark results change between runs?
Because of factors like JavaScript engine optimization, caching, system load, and background tasks. That is why multiple runs are better than one.
Can I use console.time() instead?
Yes, for quick debugging. But performance.now() is usually better when you want to store or process timing values in your own code.
Mini Project
Description
Build a small timing utility that measures how long different functions take to run. This project demonstrates how to use performance.now() in a reusable way instead of rewriting timing code every time.
Goal
Create a reusable function that measures synchronous and asynchronous tasks and prints their execution times in milliseconds.
Requirements
- Create a function to measure a synchronous callback.
- Create a function to measure an asynchronous callback.
- Display the task name and execution time.
- Test the utility with one CPU-based function and one async function.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.