The myth of evil ‘for loops’ and ‘try-catch blocks’ in JavaScript

Since the introduction of Redux and other popular libraries like RxJS, Functional Programming has been getting increasingly popular in JavaScript. This has been a mostly positive trend, however, it may have been taken a bit too far in some cases.

One of the most controversial recent FP trend in JavaScript is the “for loops and try-catch blocks are evil” trend.

Proponents of this trend want to force developers to always use functions like Array.prototype.forEach, Array.prototype.map, Array.prototype.reduce, etc… instead of old school for and while loops.

Yes, even if you want to do something as simple as creating an array of integers, you need to use some crazy tricks like this (e.g. a highly up-voted answer on Stack Overflow):

// Apparently this is better than using a 'for loop':
Array.apply(null, {length: 10}).map(Number.call, Number)

This trend may have been somewhat more useful a few years ago, but ironically, it is gaining momentum at the same time as it is becoming technically irrelevant.

Hype trends don’t happen without a reason, so it’s important to understand what reasoning may have kick-started them.

Note that in some of the examples below, you can replace myAsyncFunction with a setTimeout(..., 0) to test things out for yourself.

Why the for loop *was* evil

// Because:
for (var i = 0; i < 10; i++) {
myAsyncFunction(function () {
// i is always 10???
console.log(i);
});
}

Why the for loop is *no longer* evil

// Because: (just using let instead of var)
for (let i = 0; i < 10; i++) {
myAsyncFunction(function () {
console.log(i); // i is correct; logging from 0 to 9 inclusive
});
}

Why the try-catch block *was* evil

try {
myAsyncFunction(function () {
throw new Error('This is a very important error.')
});
} catch (error) {
// This will never run :(
console.log('ERROR!', error);
}

Why the try-catch block is *no longer* evil

// Because: (thanks to async/await)
try {
await myAsyncFunction();
} catch (error) {
// This actually runs!
console.log('ERROR!', error);
}

Why we need for and while loops

If you need to execute a bunch of async operations one at a time (serially):

for (let data of myArray) {
await myAsyncFunction(data);
}

This is not the same as:

myArray.forEach(async (data) => {
await myAsyncFunction(data);
});

In the first case, each invocation of myAsyncFunction will wait for the previous invocation to finish. In the second case, all the myAsyncFunction calls will run in parallel.

Summary

The new let keyword and async/await features of JavaScript make for loops, while loops and try-catch blocks safe again.

Moral of the story

The moral of the story is that if you work in the technology industry, things change fast so you shouldn’t follow a trend unless you can justify:

  • Why it came into existence.
  • Why it is still relevant today.