A Metaphorical Introduction to Functional JavaScript

A Metaphorical Introduction to Functional JavaScript

A Metaphorical Introduction to Functional JavaScript - Functional JavaScript isn't a tool, framework, 3rd-party addon, npm module, or anything else you'd add on. Functional Programming is an approach for writing code, and Functional JavaScript (FJS) is how to use that approach for JavaScript.

A Metaphorical Introduction to Functional JavaScript - Functional JavaScript isn't a tool, framework, 3rd-party addon, npm module, or anything else you'd add on. Functional Programming is an approach for writing code, and Functional JavaScript (FJS) is how to use that approach for JavaScript.

Like all approaches, it has benefits and drawbacks, tradeoffs one makes, people who like and dislike it, and different lobbying groups in international governments.

I'm firmly in the "like" camp for FJS. I've been writing JavaScript (poorly and otherwise) for several years and wish I'd learned about it from the start. I've found the benefits of FJS well worth the learning curve, and it's resulted in code that's more readable, flexible, and maintainable. I struggled to nail down what it means to write FJS, but once I did I couldn't go back.

From the name, you'd expect Functional Programming to just be about writing lots of functions. In a way that's true, but there are several rules one must follow to achieve that. Rules that are often hard to understand both at first glance and after some Google searches.

  1. Use Pure Functions
  2. Don't Mutate State
  3. Declarative, not Imperative
  4. Higher Order Functions

In this article, I'm going to try and break down these elements of FJS in ways that are easier to understand. This isn't an exhaustive guide by any means but is meant to be a jumping off point so people can better understand more detailed, thorough resources to learn FJS.

Let's begin!

Keep Functions Pure

Using Pure Functions and avoiding State Mutation are perhaps the most important parts of writing FJS. Instead of starting with the usual definitions, I'm going to indulge myself and explain them with an imaginary dinner party.

An Angel and a Mutant Enter a Dinner Party...

First, imagine an angel. The angel radiates a soft, pure white with glittering wings and a serene face. They bob gently over the ground and moves with smooth yet purposeful grace. No living person can see this angel, and it passes through anything it touches.

Let's say this angel was in the corner of a crowded dinner party. You tell the angel they need to move across the room and stand next to the punch bowl. The angel nods and starts floating toward this spot. No one can see or touch it. No one's conversations are disturbed and no one needs to move out of their way. Thanks to all this, the angel takes the shortest possible route to the punch bowl. If the dinner party filled with entirely new guests, the angel could do this again along the exact path.

Now imagine almost the exact opposite of this angel: a radioactive mutant. The mutant was once human but has transformed into something grotesque. They could have any grotesque feature you want: waving tentacles, eyes all over their back, feet that are webbed and clawed, a t-shirt with a pop culture reference decades out of date, or they own a real estate business. Whatever you choose, this mutant is scary and you can't look at it too long.

Let's say this mutant had the same task: move from the corner of a dinner party to the punch bowl. You could imagine how horrible that would go. People would be screaming and pushing away from the mutant constantly. Plus its radioactivity would start giving random people different mutations, and guests would run from them too. The mutant would need to push and shove along an unpredictable path to reach that spot. If you restarted this scenario at a party with different guests, the radiation would make different people mutate, and the humans would panic in new ways. The mutant would need to take a different, but just as rough, route to the punch bowl.

To be a Pure Function

As you may have guessed, the angel has all the qualities of a pure function.

  1. No external state is changed. The angel goes across the room without anyone or anything changing. A pure function does its job without anything outside the function changing either.
  2. The same input has the same results. The angel takes the same exact path to the same path every time. A pure function, when given the same input, returns the same result each time.

And if the name wasn't a big enough giveaway, the mutant has all the qualities of a function that mutates state.

  1. Variables outside the function are affected. The mutant affects other people by scaring party guests and making other people mutate. Impure functions change variables that exist outside of them, on purpose or by accident.
  2. The same input can have different results. The mutant makes random people mutate, which will change the type of panic and therefore the path the mutant takes each time. Impure functions return different values due to how they affect outside variables each time.

Here's some actual JavaScript to drive all this home. Is the below addNumberfunction an angel or a mutant?

let number = 0;

let addNumber = x => {
  number += x;
  return number;
}

addNumber is a mutant since it changes number, a variable outside the function. These changes mean we could run this function twice with the same parameter and get different results.

addNumber(5) // 5
addNumber(5) // 10 (which is not 5)

If we wanted a pure angel function, we'd rewrite one like this.

let number = 0;

let addNumbers = (x, y) => x + y;

Instead of relying on an outside variable, we make both numbers variables that we pass in. This keeps all the function's variables in its own scope, and the same inputs give the same results.

addNumbers(number, 5); // 5
addNumbers(number, 5); // 5 (which is 5)!

FJS uses pure functions since they're like angels. Angels are good and mutants are bad. Don't let the mutants win. Use pure functions.

Be Declarative, not Imperative

I've had a hard time understanding the difference between declarative and imperative programming for the longest time. Before anything else, know that declarative and imperative programming are both valid approaches with their own ups and downs. Functional programming just favors being declarative.

As for the specifics, let's imagine two different beings again. This time it'll be a southern belle and a stable boy. We ask both of them to fetch us a bucket of milk and give them an empty bucket for the job.

The southern belle is haughty and hates getting her hands dirty. She handles this task by summoning her servant and saying "I do declare, if there is a cow outside, bring me a bucket of milk with a bucket like this!" The servant bows, examines the bucket, leaves, and returns with a bucket of milk. It's in a different bucket that looks identical to the one we gave her. The southern belle takes the milk and hands it to us.

The stable boy enjoys getting his hands dirty. He handles this task by taking the bucket, going to the barn, finding a cow, and going through all the motions to milk it. He chooses the right cow, milks the cow, fills our bucket with the milk, and carries it back to us himself.

Both people got us the bucket of milk, albeit in very different ways. The southern belle wasn't involved in the actual steps to get the milk, she focused on what she needed and used her servant to get it. Meanwhile, the stable boy focused on how to get the milk and went through all the steps.

At its core, that's the difference between declarative and imperative programming. Declarative programming solves a problem based on what it needs, and avoids direct DOM or variable manipulation. This is a good fit for pure functions since they're about giving you new data and objects to avoid mutating state. Meanwhile, imperative programming changes the DOM and manipulates state, but in a more focused way that gives better control when done right.

When you're not writing JavaScript to manipulate DOMs, I've approached declarative programming by declaring new variables instead of mutating existing ones.

For example, let's say you had to write a function that doubled all numbers in an array. An imperative approach would manipulate the given array directly and redefine each item.

const doubleArray = array => {
  for (i = 0; i < array.length; i++) {
    array[i] += array[i];
  }

  return array;
}

This is the code equivalent of the stable boy taking the array, doubling each item in it, and giving you a mutated version of the array. The declarative version looks quite different.

const doubleArray = array => array.map(item => item * 2);

This declarative version gives the work to another function, in this case, map, which already has built-in logic to go through each item (we'll cover this in a bit). This returns an array separate from the original and the first array isn't mutated, making this a pure function! As a result, this function is simpler, cleaner, safer to use, and much more in line with FJS.

The southern belle is simply declaring she wants an array with double the values, and her servant (map) is returning a different array to meet her request.

Use the Right FJS Tools

Okay, enough metaphors. Let's get into the nitty-gritty-codey ways to write FJS. First let's cover some of the tools you'll be using the most to write your pure, imperative functions.

Arrow functions

Arrow functions were added with ES6 and their main benefit is a shorter, sweeter function syntax. FJS means writing lots of functions, so we might as well make it easier.

Before arrow functions, a basic "add five to a number" function would look like this.

const addFive = function(number) {
  return number + 5;
}

Simple functions like this can be written without the function keyword or the explicit return.

const addFive = number => number + 5;

The variable first identifies the arguments, in this case number. You could also use parenthesis for no arguments, like with (), or for multiple arguments, like with (number1, number2).

After that is the arrow, shown as =>. Whatever expression follows is automatically returned, in this case, that's number with five added.

More complex functions can use braces for extra lines, but you'll lose the implicit return and need to write it out. Not as good, but still better than the first syntax.

const addFive = number => {
  // more code here
  return number + 5;
};

Array Prototype Methods

Each array has several powerful tools built into them that'll cover most, if not all, of your FJS needs. Calling them returns new, modified arrays you can easily assign to new variables. They're similar to the southern belle's servant from the declarative metaphor - they're already there, do the work for you, and give you new objects based on what you started with.

Let's start with one of the most basic methods, map. It takes each item in an array, runs it through a function to get a new value, and replaces the old value with this new one. Once it does that for each item, it returns a newly updated array.

Here's a tweaked example of the declarative code example from before, but using map to double array values.

[2, 4, 6].map(item => item * 2);
// [4, 8, 12]

You're basically using map to pull out each array object as item and say "Replace this item with item * 2."

You could also write the doubling function separately to make the code even more functional. Plus you can assign what map returns to an entirely different variable.

const double       = (item) => item * 2,
      array        = [2, 4, 6],
      doubledArray = array.map(double);

console.log(array);        // [2, 4, 6]
console.log(doubledArray); // [4, 8, 12]
// The original array hasn't been mutated!

There are many great methods to learn, and covering them all is another post altogether. Check out my study repo for a quick look at different array prototype methods, or just google around for them!

Bonus: Chain Array Prototype Methods

One more fun fact you should know: array methods can be chained together! This lets you combine different array changes quickly and without breaking FJS rules.

Let's say we wanted to double each array value, then filter out the ones lower than five (filter is another useful method to learn later). We just need to write one extra function and add another method to our array.

const double         = (item) => item * 2,
      higherThanFive = (item) => item > 5,
      array          = [2, 4, 6],
      doubledArray   = array.map(double).filter(higherThanFive);

console.log(array);        // [2, 4, 6]
console.log(doubledArray); // [8, 12]

Lastly, many people (like myself) often use different spacing when chaining to keep it readable. The below variable is the same as the above but easier to understand at a glance.

doubledArray   = array
                  .map(double)
                  .filter(higherThanFive);

Remember Reduce

reduce is a prototype method I want to highlight since it's arguably the most powerful. On its own, it can recreate almost any other prototype method and can make more complex and powerful ones. Reduce is another blog post too, so once again I refer you to my study notebook (or Google) to quickly learn more about <a href="https://maxx1128.gitbook.io/study-notebook/javascript/reducefunction" target="_blank">reduce</a>. Just remember these important facts:

  1. Reduce is great for complex merging or manipulation of data, as long as you make sure another prototype method doesn't already do what you need.
  2. Everything about other prototype methods, such as chaining and passing in functions, applies to reduce.

reduce is one of your most powerful FJS tools, so learn it well.

Higher-order functions

Now that we have these new ways to write functions, next is new ways to manage them. One of the best methods for FJS is making use of higher-order functions, of HOFs. Several code examples so far have made use of HOFs, but having a clearer definition of it helps with making full use of it.

HOFs are functions that take other functions as arguments. Remember that functions are first-class citizens in the JavaScript kingdom, so they can be:

  • Saved to variables
  • Passed to other functions
  • Returned from other functions

I wish I'd learned to make use of HOFs earlier in my career. It helped me write more functions that abstracted logic away to make programs more readable and maintainable. So getting into the mindset of "functions passing around functions" is great for FJS, but also better JavaScript in general.

Let's say I needed to test if many numbers were divisible by a group of other numbers. One's first instinct may be to write each function out like this.

const divisibleby3 = (n) => n % 3 === 0,
      divisibleby5 = (n) => n % 5 === 0,
      divisibleby7 = (n) => n % 7 === 0;

divisibleBy3(6);  // true
divisibleBy5(14); // false
divisibleBy7(28); // false

This works, but you have to repeat the same expressions over and over. A solution using HOFs would look like this and get the same results.

const divideBy = (x) => (y) => y % x === 0;

const divisibleBy3 = divideBy(3),
      divisibleBy5 = divideBy(5),
      divisibleBy7 = divideBy(7);

divisibleBy3(6);  // true
divisibleBy5(14); // false
divisibleBy7(28); // true

This is complicated, so let's break it down.

  1. The divideBy function takes one argument, x, and saves it while returning another function. So when we call divideBy(3), we're saving x as part of the function being returned every time.
  2. We can save this function to a variable, such as divisibleBy3. This makes sense since we've already made 3 part of the function returned each time.
  3. Since divideBy returns a function, we can now call divisibleBy3 like a normal function. It uses both the y variable it gets at the call, and the x variable it got before.

All this is an example of "currying" functions or functions that return other functions until they eventually give final functions like divisibleBy3. As you can see, currying in JavaScript has many examples of HOFs in use. Currying is great if you have functions with some, but not all, of their logic in common. You can create a template with the logic they have in common (a comparison operator) and pass in logic specific to each one (the number used in the operation).

If you don't want to save the first part of a curried function to a variable, you can use the shortcut of calling multiple arguments at the same time.

const divideBy = (x) => (y) => y % x === 0;

divideBy(3)(6);  // true
divideBy(5)(14); // false
divideBy(7)(28); // true

As you can see, curried functions help your code whether you use them once or dozens of times in your program!

Curried functions are also tough to understand, so I have another note that better breaks currying down if you need it.

Here's another example of HOFs that takes a function as the fn argument. The function accepting it refers to it like any other variable.

const performMultipleTimes = (times, x, fn) => {
  for (let i = 0; i < times; i++) {
    fn(x);
  }
}

This function takes three arguments:

  1. The number of times to repeat the loop
  2. The argument passed into the fn function
  3. The fn function

The function is being called inside the loop, so performMultipleTimes lets us call a function many times while only writing it once. All we need to do is pass one function another function, which we can do by storing the function in a variable. HOFs at work once again!

const logString = s => console.log(s);

performMultipleTimes(3, 'Greetings!', logString);
// Greetings!
// Greetings!
// Greetings!

If you don't use this function anywhere else and don't want to save it for later, you can also pass it directly. You can do this with or without the bracket syntax.

performMultipleTimes(3, 'Greetings!', (s) => console.log(s));

performMultipleTimes(3, 'Greetings!', (s) => {
  const newString = `I am here to say '${s}'`;
  console.log(newString);
});

Understanding HOFs is great but is especially for FJS. This style is about focusing on the power of functions, and passing functions around effectively can multiply their power and modularity.

However, this was hard to grasp for me and it might be the same for you. So if you (understandably) still have trouble, this chapter from Eloquent JavaScript does a great job breaking HOFs down further.

FJS is a Style, not an Absolute

A final note on FJS: it's a style of writing JavaScript that exists on a spectrum. It isn't simply "this is or is not FJS." You can write code with elements of FJS (like pure functions or being declarative) without needing to follow the rules. Each is a preference that, as they're put together, make your JavaScript closer to the functional paradigm.

FJS can be tough to grasp, as you can tell by the number of links I reference for extra reading. But understanding these four topics will help you build a solid foundation for learning more. This is what holds true for me since they made everything click into place for every other article I read on FJS. Hopefully, this post can do the same for anyone else looking to learn and use it.

If you really want to go deeper into FJS, I recommend [Kyle Simpson's book "Functional-Light JS."](https://github.com/getify/Functional-Light-JS "Kyle Simpson's book "Functional-Light JS."") It goes into much deeper detail on functional programming and JavaScript, and you can read it for free on Github!

Mobile App Development Company India | Ecommerce Web Development Company India

Mobile App Development Company India | Ecommerce Web Development Company India

Best Mobile App Development Company India, WebClues Global is one of the leading web and mobile app development company. Our team offers complete IT solutions including Cross-Platform App Development, CMS & E-Commerce, and UI/UX Design.

We are custom eCommerce Development Company working with all types of industry verticals and providing them end-to-end solutions for their eCommerce store development.

Know more about Top E-Commerce Web Development Company

JavaScript developers should you be using Web Workers?

JavaScript developers should you be using Web Workers?

Do you think JavaScript developers should be making more use of Web Workers to shift execution off of the main thread?

Originally published by David Gilbertson at https://medium.com

So, Web Workers. Those wonderful little critters that allow us to execute JavaScript off the main thread.

Also known as “no, you’re thinking of Service Workers”.

Photo by Caleb Jones on Unsplash

Before I get into the meat of the article, please sit for a lesson in how computers work:

Understood? Good.

For the red/green colourblind, let me explain. While a CPU is doing one thing, it can’t be doing another thing, which means you can’t sort a big array while a user scrolls the screen.

This is bad, if you have a big array and users with fingers.

Enter, Web Workers. These split open the atomic concept of a ‘CPU’ and allow us to think in terms of threads. We can use one thread to handle user-facing work like touch events and rendering the UI, and different threads to carry out all other work.

Check that out, the main thread is green the whole way through, ready to receive and respond to the gentle caress of a user.

You’re excited (I can tell), if we only have UI code on the main thread and all other code can go in a worker, things are going to be amazing (said the way Oprah would say it).

But cool your jets for just a moment, because websites are mostly about the UI — it’s why we have screens. And a lot of a user’s interactions with your site will be tapping on the screen, waiting for a response, reading, tapping, looking, reading, and so on.

So we can’t just say “here’s some JS that takes 20ms to run, chuck it on a thread”, we must think about where that execution time exists in the user’s world of tap, read, look, read, tap…

I like to boil this down to one specific question:

Is the user waiting anyway?

Imagine we have created some sort of git-repository-hosting website that shows all sorts of things about a repository. We have a cool feature called ‘issues’. A user can even click an ‘issues’ tab in our website to see a list of all issues relating to the repository. Groundbreaking!

When our users click this issues tab, the site is going to fetch the issue data, process it in some way — perhaps sort, or format dates, or work out which icon to show — then render the UI.

Inside the user’s computer, that’ll look exactly like this.

Look at that processing stage, locking up the main thread even though it has nothing to do with the UI! That’s terrible, in theory.

But think about what the human is actually doing at this point. They’re waiting for the common trio of network/process/render; just sittin’ around with less to do than the Bolivian Navy.

Because we care about our users, we show a loading indicator to let them know we’ve received their request and are working on it — putting the human in a ‘waiting’ state. Let’s add that to the diagram.

Now that we have a human in the picture, we can mix in a Web Worker and think about the impact it will have on their life:

Hmmm.

First thing to note is that we’re not doing anything in parallel. We need the data from the network before we process it, and we need to process the data before we can render the UI. The elapsed time doesn’t change.

(BTW, the time involved in moving data to a Web Worker and back is negligible: 1ms per 100 KB is a decent rule of thumb.)

So we can move work off the main thread and have a page that is responsive during that time, but to what end? If our user is sitting there looking at a spinner for 600ms, have we enriched their experience by having a responsive screen for the middle third?

No.

I’ve fudged these diagrams a little bit to make them the gorgeous specimens of graphic design that they are, but they’re not really to scale.

When responding to a user request, you’ll find that the network and DOM-manipulating part of any given task take much, much longer than the pure-JS data processing part.

I saw an article recently making the case that updating a Redux store was a good candidate for Web Workers because it’s not UI work (and non-UI work doesn’t belong on the main thread).

Chucking the data processing over to a worker thread sounds sensible, but the idea struck me as a little, umm, academic.

First, let’s split instances of ‘updating a store’ into two categories:

  1. Updating a store in response to a user interaction, then updating the UI in response to the data change
  2. Not that first one

If the first scenario, a user taps a button on the screen — perhaps to change the sort order of a list. The store updates, and this results in a re-rendering of the DOM (since that’s the point of a store).

Let me just delete one thing from the previous diagram:

In my experience, it is rare that the store-updating step goes beyond a few dozen milliseconds, and is generally followed by ten times that in DOM updating, layout, and paint. If I’ve got a site that’s taking longer than this, I’d be asking questions about why I have so much data in the browser and so much DOM, rather than on which thread I should do my processing.

So the question we’re faced with is the same one from above: the user tapped something on the screen, we’re going to work on that request for hopefully less than a second, why would we want to make the screen responsive during that time?

OK what about the second scenario, where a store update isn’t in response to a user interaction? Performing an auto-save, for example — there’s nothing more annoying than an app becoming unresponsive doing something you didn’t ask it to do.

Actually there’s heaps of things more annoying than that. Teens, for example.

Anyhoo, if you’re doing an auto-save and taking 100ms to process data client-side before sending it off to a server, then you should absolutely use a Web Worker.

In fact, any ‘background’ task that the user hasn’t asked for, or isn’t waiting for, is a good candidate for moving to a Web Worker.

The matter of value

Complexity is expensive, and implementing Web Workers ain’t cheap.

If you’re using a bundler — and you are — you’ll have a lot of reading to do, and probably npm packages to install. If you’ve got a create-react-app app, prepare to eject (and put aside two days twice a year to update 30 different packages when the next version of Babel/Redux/React/ESLint comes out).

Also, if you want to share anything fancier than plain data between a worker and the main thread you’ve got some more reading to do (comlink is your friend).

What I’m getting at is this: if the benefit is real, but minimal, then you’ve gotta ask if there’s something else you could spend a day or two on with a greater benefit to your users.

This thinking is true of everything, of course, but I’ve found that Web Workers have a particularly poor benefit-to-effort ratio.

Hey David, why you hate Web Workers so bad?

Good question.

This is a doweling jig:

I own a doweling jig. I love my doweling jig. If I need to drill a hole into the end of a piece of wood and ensure that it’s perfectly perpendicular to the surface, I use my doweling jig.

But I don’t use it to eat breakfast. For that I use a spoon.

Four years ago I was working on some fancy animations. They looked slick on a fast device, but janky on a slow one. So I wrote fireball-js, which executes a rudimentary performance benchmark on the user’s device and returns a score, allowing me to run my animations only on devices that would render them smoothly.

Where’s the best spot to run some CPU intensive code that the user didn’t request? On a different thread, of course. A Web Worker was the correct tool for the job.

Fast forward to 2019 and you’ll find me writing a routing algorithm for a mapping application. This requires parsing a big fat GeoJSON map into a collection of nodes and edges, to be used when a user asks for directions. The processing isn’t in response to a user request and the user isn’t waiting on it. And so, a Web Worker is the correct tool for the job.

It was only when doing this that it dawned on me: in the intervening quartet of years, I have seen exactly zero other instances where Web Workers would have improved the user experience.

Contrast this with a recent resurgence in Web Worker wonderment, and combine that contrast with the fact that I couldn’t think of anything else to write about, then concatenate that combined contrast with my contrarian character and you’ve got yourself a blog post telling you that maybe Web Workers are a teeny-tiny bit overhyped.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

An Introduction to Web Workers

JavaScript Web Workers: A Beginner’s Guide

Using Web Workers to Real-time Processing

How to use Web Workers in Angular app

Using Web Workers with Angular CLI