Benchmarking JavaScript Loops and Methods (Part 1)
Michael McShinsky
Posted on June 15, 2020
Part 2 is now available here!
Introducing Loops and Methods
We’re going to take a look at the various loops and methods provided in JavaScript to find out which ones are more efficient for the data you are iterating over. The reason I’ve taken the time to put this together comes from watching the evolution of developers and how they use and form opinions about these various loops and methods.
Everyone starts with your basic for loop
. Once a new developers learns this, their minds are blown and life becomes easier. This mind blown experience happens over and over as new methods are introduced. What is interesting, is that as soon as new loop and methods are introduced (while, forEach, map, filter, etc…), the basic for loop
is left behind in the dust for a long time. This happens anywhere from the first few weeks to the next few months. It will either take a long time or a specific experience in data manipulation for a developer to comes back and consider the basic for loop
again in order to meet their objectives.
For this reason, we are going to see if there is any justification to only using methods such as forEach
and map
, or if there is any merit in sticking with the tried and true for loop
.
Data Types
We’re going to tackle each of these loops and methods to discover their advantages and disadvantages against Primitive and Non-primitive data types. If you need a refresher on these data types, here is a list you generally work with.
Primitives
Non-Primitive
Finding a Value in an Array
Our benchmarks will show us how efficient our loops are at retrieving, depending on the return value, the value or the index of the value from the array. The loops we will use are:
Let’s start with a small example that displays each of these loops finding a primitive value a from sample array. Note, we’re going to be a little more verbose than some of the "one liner" functions out there in order to capture more values.
Examples of Primitive Arrays:
let namesArray = ['Abe', 'Beth', 'Cody', 'Daniel'];
let textArray = ['Dog', 'Cat', 'Horse', 'Cow'];
let numbersArray = [1, 2, 3, 4];
Starter Code
// Objectives:
// 1. Find the value 7
// 2. Find the index of 7
const OBJECTIVE_NUMBER = 7;
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let foundValue;
let foundIndex = -1;
Let’s give ourselves an example of the kind of code we’ll be using for benchmarking. For a full list of loop and method examples, click here!
"for loop" example
// Using array and variables from base code block above…
for (let index = 0; index < arr.length; index++) {
const value = arr[index];
if(value === OBJECTIVE_NUMBER) {
foundValue = value;
foundIndex = index;
break;
}
};
console.log(foundValue); // expected output: 7;
console.log(foundIndex); // expected output: 6;
Benchmarking the Code
Now that we have a base understanding of each of the loops and the possibilities they bring to the table, we can see how they perform against small and large data sets. We’re going to include map, filter, and reduce, even though they are being used in an anti-pattern fashion in order to demonstrate performance across the board. We’ll also benchmark our iterations at finding the value near the start and end of the array for every loop and method. We’ll also test them on different browsers to measure the performance of each browser’s JavaScript engines (Chakra, V8, and SpiderMonkey) which are iterating and optimizing our loops in the background.
Arrays we will be using:
Array 1: 100 primitive values;
Array 2: 1,000 primitive values;
Array 3: 10,000 primitive values;
Note: In Part 2, we’ll look at the same loops but against non-primitives (objects, arrays, functions) and measure performance against them.
Finalized Results
Before we talk about the following results, please remember that there will be variances on performance depending on the hardware and software per user. As a result of this, we as developers should plan for the worst case scenarios in order to provide an optimized experience to users across all platforms and devices. With that in mind, let’s take a look at how our loops performed when searching for a primitive value inside an array.
Note: The graphs represent each loop or method and how many operations per second (op/s) are ran within a given timeframe.
Chrome
Edge
Firefox
Breaking Down the Results
After looking at the charts, we can make a few general conclusions:
As data sets get larger,
map
,reduce
, andfilter
perform the worst when used against their intended purpose or definition.Against small arrays, Firefox’s engine (SpiderMonkey) is optimized across all methods to iterate over arrays and find values both at the start and end of said arrays.
lastIndexOf
performs as expected. It is worse when searching the start of an array and the best when searching for end values. Since this is expected, we will remove this method when comparing for overall performance.
Small Sized Arrays
Let’s start with small arrays for some overall takeaways.
Edge:
forEach
,map
, andreduce
perform the best.Chrome:
forEach
,map
, andreduce
perform the best.Firefox: all methods except
map
,filter
andreduce
perform well, but not by much.Overall Performer:
forEach
Medium Sized Arrays
We notice next, that with medium sized arrays and especially when looking for values near the end of the array, performance starts to shift a lot across all the loops and methods.
Edge:
indexOf
andincludes
perform better followed bywhile
,do…while
,for
, andfor…of
.Chrome:
indexOf
andincludes
take the cake for performance followed byfor
,while
anddo…while
.Firefox: A higher performance is recorded here than in Edge and Chrome.
for
,while
,indexOf
, andincludes
are all high performers.Overall Performers:
indexOf
andwhile
, since we’re are generally looking from the front to back for our value.
Large Sized Arrays
Finally, we see a much higher drop off in performance as our array grows in size.
Edge:
for
,while
, andindexOf
perform the best. Most other loops and methods end up doing poorly.Chrome:
for
,while
,indexOf
andincludes
stay on top while yet again, we see most other methods failing to perform at the same level.Firefox:
for
,while
, andindexOf
once again are top contenders with the same drop off seen with most of the remaining loops and methods.Overall Performers:
for
andwhile
.
Conclusion
Hopefully, as a result of seeing the data, we can all make better decisions on the methods we want to use against various data sets. If we are working with data that may grow over time and we have to iterate over all that data, it may be appropriate to come back to the reliant for loop
that has always been there for us. Especially since you can take advantage of it's inherit ability to stop to loop with break
and return
once you have finished your intended action. While it may not look pretty, it will always be handy.
In Part 2, we will show similar data, but introduce searching non-primitives to see how the results change. This should be even more relevant to daily tasks since a lot of the data we work with comes back as JSON arrays full of objects from a database.
If you found this helpful or useful, please share a 💓, 🦄, or 🔖. Thanks!
Posted on June 15, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.