What's the performance cost of a function call?

In addition to file size, one reason it can be tempting to compromise on readability is performance.

However, this article demonstrates why that's a bad idea. Keep your focus on writing readable code and only optimize if there's a clear benefit to the end user.

How much does splitting code into small functions cost?

This jsFiddle compares two similar bits of code. Both add two numbers ten million times.

The first code snippet calculates the sum directly inside a for loop, while the second one calls an add function:

function (){
  var c;
  for (var i = 0; i < 10000000; i++) {
    c = a + i;
  }
}

function (){
  var c;
  for (var i = 0; i < 10000000; i++) {
    c = add(a, i);
  }
}

So what's the cost of an extra 10 million function calls? In this case, there's no extra overhead:

2.77ms - Addition in for loop
2.76ms - Addition in function
(Results vary by how each browser treats the code above.)

That's because of an optimization called inlining that's performed by all modern JavaScript engines.

The browser's JavaScript engine looks at our code and decides that it's more efficient to replace the function call with direct addition.

This means that both code snippets are ultimately run in the same way, even though the code we wrote is different. Consequently, they take the same amount of time to run.

If you're interested you can play around with Node to explore the effect of function inlining.

Cost of using forEach instead of a for loop

There's no guarantee that the JavaScript engine will optimize your code.

Even the example above isn't always optimized. It depends on the decision made by the JavaScript engine.

Take a look at this example using forEach on a list containing ten million numbers, doing the same additions as before.

5.4ms - Direct addition
9.3ms - Add function
162.5ms - ForEach

ForEach is 30 times slower than a for loop! Why would you ever use forEach?

The answer is that most of the time the cost of your looping logic is completely negligible.

The example above iterates over 10 million values. But that's a very rare scenario. Even having 10 thousand list items is unusual, but forEach would only take a fraction of a millisecond to go through all 10 thousand items.

In addition to that, the performance cost of the looping logic is small compared to other computations. Take this example which generates a small bit of HTML code instead of just performing an addition:

1961ms - For Loop
2188ms - ForEach

Now forEach is only 12% slower than a for loop. That's because generating HTML code takes much more time than iterating over a list.

Summary

As a general rule, there's no need to worry about the performance impact of function calls or list iterations.

That's because of three reasons:

  • The JavaScript engine will optimize your code
  • Most of your lists will contain fewer than 1000 items
  • The cost of bare function calls is tiny compared to other computations

Jeff Atwood also wrote an interesting article about micro-optimization and concluded that

you should be more worried about the maintainability and readability of your code than its performance. And that is perhaps the most tragic thing about letting yourself get sucked into micro-optimization theater -- it distracts you from your real goal: writing better code.

Focus on writing readable code! Other people are much more likely to struggle with your code than computers are.

How to handle performance issues if they do arise

Use profiling tools when you do run into performance problems. The profiling features included in Google Chrome usually give you a good idea of what part of your code is most CPU intensive.

Once you've identified the slowest part of your program you can focus your efforts there.

Most performance improvements won't negatively impact readability!

If you have to make a code change that reduces readability, leave a comment to explain why. This allows future developers to understand the advantage of that choice over a more readable alternative.