Stop Telling People For Loops Are Bad
Dwayne Charrington
Posted on November 13, 2019
Something had to be said. From time-to-time I see a post appear that goes along the lines of, "Loops are bad, you should be using filter, map and reduce instead" - it makes me grind my teeth every time I see a post try and argue that you should be using these functional methods for looping everything.
Yes, these functional methods have a purpose and valid use. I am not arguing that you should not use them, but I am arguing against using them for everything. In many instances, if you want to write performant code, a for loop is always going to be the faster option.
The whole purpose of methods such as map
, filter
and reduce
is preventing the mutation of what gets passed into them. In FP (functional programming) style, passing in an array into these methods will return a new collection and leave the original untouched.
In the case of map
(because it seems to be the most abused and least performant) the difference can be significant in comparison to a for loop. The reason is map will create a new copy, fire off a callback on every iteration and consumes more memory. A for loop is working off of whatever you're iterating, so it has no overhead almost.
Someone has created a repository where they have done the comparison work, the results for large results of data are astounding (and not at all surprising if you know how these methods work).
In my web applications, I tend to use map
, filter
and reduce
a lot more these days than I used to. I am mindful however that a for loop is a better option in some instances because a for loop can do things these methods cannot.
Breaking the loop
You might already know this, but a for loop can be stopped using the break
keyword. If you're using a for loop to iterate over an array until you find a specific item or a certain number of iterations have run, you can stop the loop by executing break
in your loop.
On the contrary, map
, filter
and reduce
by their very nature cannot be stopped; they will iterate until they have gone over every item in your array.
Asynchronous loops
A for loop can easily be used with async/await, meaning you can pause the loop and make it wait for a promise to resolve before proceeding to the next value being iterated over.
Functional methods map
, filter
and reduce
are turbulent when you try throwing async/await into the mix. I think you can get it to somewhat work in a reduce
if you await the accumulator, but it doesn't feel right.
A for loop makes it easy, so why make things harder on yourself? And yes, async/await works with all kinds of for loop.
Are you doing this? Stop it.
async function loadValues() {
let myValues = await getValuesFromApi();
myValues = myValues.map(value => {
value.total = value.price * value.quantity;
return value;
});
}
The number of times I have seen a map used to iterate over an array of objects, only for the result to be reassigned to the very array being mapped is too many to count. The whole point of map
is to create a new copy of the array, except many people use map
as a loop and reassign the result back to the original variable instead of a new one.
If you are doing this, stop it already. Just use a for loop, because that is exactly what you are doing and you are gaining no benefit from using map
in this instance.
Conclusion
In many instances, you won't notice a performance hit if you use any of the aforementioned functional methods over a traditional for loop. If you're not dealing with tens or hundreds of thousands of pieces of data, you won't be able to see a 100ms difference.
Write whatever you are comfortable writing and then if you notice performance is less than ideal, you can use your browser developer tools and common sense to pinpoint which areas of your application could be optimised.
Remember: premature optimisation is the root of all evil
Posted on November 13, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.