duhan
Blog

Fastest Loop in JavaScript

In this post, I wanted to test whether choosing the right loop can actually make your app faster.

Since array access time is O(1), they’re already efficient but which loop handles them best?

Now you might say: “It doesn’t even matter. Machines are fast enough.” True in most cases. But not everyone has a high-end device or blazing-fast network. Optimization still matters, especially at scale.


The Experiment

Here are the loop types we’re comparing:

  • for
  • for of
  • for in
  • forEach
  • while

Test case: Loop through 1,000,000 numbers, and repeat that 1000 times for each loop type.

I ran the benchmark in two environments:

Each loop is measured with:

  • Average time
  • Median time
  • Standard deviation

The Setup

Loop types are measured like this:

measureLoopType("for-of");
measureLoopType("for");
measureLoopType("for-in");
measureLoopType("forEach");
measureLoopType("while");

No external packages used. Just a simple getStats function that returns averages, medians, and std dev:

const getStats = (totalDurations) => {
  const averageDuration =
    totalDurations.reduce((acc, curr) => acc + curr, 0) / totalDurations.length;

  const sortedDurations = [...totalDurations].sort((a, b) => a - b);
  const mid = Math.floor(sortedDurations.length / 2);
  const median =
    sortedDurations.length % 2 !== 0
      ? sortedDurations[mid]
      : (sortedDurations[mid - 1] + sortedDurations[mid]) / 2;

  const mean = averageDuration;
  const squareDiffs = totalDurations.map((value) => (value - mean) ** 2);
  const avgSquareDiff =
    squareDiffs.reduce((acc, curr) => acc + curr, 0) / squareDiffs.length;
  const standardDeviation = Math.sqrt(avgSquareDiff);

  return {
    averageDuration,
    median,
    standardDeviation,
  };
};

Next, define the number array and tracking map:

const numbers = Array.from({ length: 1_000_000 }, (_, index) => index + 1);
const runs = 1000;
const totalDurations = new Map();

Benchmark logic:

const measureLoopType = (type) => {
  for (let i = 0; i < runs; i++) {
    const startTime = performance.now();

    // loop goes here...

    const endTime = performance.now();
    const duration = endTime - startTime;

    if (totalDurations.has(type)) {
      totalDurations.get(type).push(duration);
    } else {
      totalDurations.set(type, [duration]);
    }
  }
};

Loop switch statement:

switch (type) {
  case "for-of":
    for (const number of numbers) {
      // Operation
    }
    break;

  case "for":
    for (let i = 0; i < numbers.length; i++) {
      // Operation
    }
    break;

  // ... other loops
}

And finally, print the results:

let results = [];

totalDurations.forEach((value, key) => {
  const stats = getStats(value);
  results.push({
    LoopType: key,
    Average: `${stats.averageDuration.toFixed(4)} ms`,
    Median: `${stats.median.toFixed(4)} ms`,
    StdDev: `${stats.standardDeviation.toFixed(4)} ms`,
  });
});

console.table(results);

Results

Bun

Bun result

Bun gave me a surprise: forEach was the fastest loop.
Its average execution time was just 0.6244 ms with a very low standard deviation, fast and consistent.

The for and while loops followed closely.
But for-in was much slower, as expected.

In Bun, forEach is the winner. Unexpected, but real.


Node.js

Node result

In Node.js, the results were more predictable:

  • while was the fastest with a median of 0.3099 ms
  • for was almost identical
  • forEach was a bit slower
  • for-in was again the slowest

Also, while had a small std dev of 0.1874 ms, showing reliable performance across iterations.

GitHub: Fastest Loop in JS


The biggest surprise: in Bun, forEach was the fastest. Breaking the usual assumptions.

It shows how runtime environments can affect performance, even in simple constructs like loops.

On the server side, choosing the right loop isn’t just a nitpick. It can help you save compute and improve latency. Test in your environment, and don’t rely on assumptions.

🔗 Related posts