Memoization in JavaScript? And how to apply it to get better code performance.

Memoization in JavaScript? And how to apply it to get better code performance.

As a programmer, we always want to write code that is robust and gives us better performance. But sometimes we face performance issues due to not applying good optimization techniques. One such technique is Memoization. Memoization offers notable performance benefits when dealing with a function that has repeated parameters. In this article, I'm going to talk about Memoization, how you can implement it and when it should be used.

Prerequisites

Before you begin reading, it will be great to know the followings:

So let's get started!!!

What is memoization?

From Wikipedia:

In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.

So, Memoization is an optimization technique that can be used to reduce extensive(time-consuming) calculations by saving previous input to something called cache and returning the result from it. When a memoized function is given the same input again, it will return the cached result without calculating from the start. Thus saving code execution time and memory.

As you can guess, Memoization is not only limited to JavaScript but is also widely supported by many other languages. It's a common concept in the programming world.

Implementing Memoization

Before seeing how Memoization works, let's look at a simple example that will demonstrate how Memoization can help us to get better performance. Consider the following function which returns the square of a number.

Normal Function

1.png

In case you are not familiar with console.time() and console.timeEnd, they are used to track how long an operation takes. Read more about them on MDN.

Here, I've invoked the function with the same input four times. Here is its completion time:

2.png

InvocationsTime Taken
First9.331ms
Second2.336ms
Third1.397ms
Fourth0.137ms

Later we'll compare this result against the memoized result.

Memoized Function

Now we are going to implement Memoization in the getSquare function. Remember that to memoize a function, it should be pure so that return values are the same for the same inputs every time.

Take a look at the following function:

3.png

Demo Output

4.png

How Memoization works?

The principal to making a function memoized function is to store its last input and output. In JavaScript environment, Memoization heavily relies on Closure and Higher-Order Functions.

Code breakdown of memoSquare() function:

  • In line 3 we have a variable named cache to store previous inputs.
  • In Line 5 we return the whole memoized function.
  • In Line 7 we check if the input is in the cache.If so, we return the cached value.cache can remember the values because of the closure it's implemented in. And this only works because the function we're working with is a pure function.
  • If we check the output of cache in line 9 of Output, we'll see that the cache object is containing all the inputs only once. For example, We have inputted value 4 multiple times but it only stored it once. If the current inputted value is in the cache then it simply returns a value. Check the Demo output screenshot.
  • From line 13 we write our function logic. In here it runs a for loop and simply returns a square of a number.
  • In line 15 we cache/store our new input value to the cache object.

Now lets checkout the completion time of memoSquare() function.

Invoking the function multiple times with same value:

5.png

Result

6.png

InvocationsTime Taken
First7.741ms
Second0.056ms
Third0.052ms
Fourth0.045ms

Normal function vs Memoized Function:

Capture.PNG

From the comparison table, you can see how Memoization grants us better performance aka execution time each time it is called with the same value. It cuts down the heavy calculations for a previous value. So it's a good idea to memoize a function that does heavy computations or is expensive on time and memory.

Use Cases

You can use Memoization in the following cases:

  • Repeated invocations of a function.
  • When you have a wide range of input values.
  • You have an idea of what will be the possible inputs.
  • Functions that involves mathematically heavy operations.
  • In recursive functions.

Tradeoffs

Like any other optimization technique, There are limitations of Memoization. In some cases, improper use of Memoization can actually harm performance. Memoization works by storing old results and it has to be stored somewhere. As a consequence, memoized functions consume additional memory. Memoization is appropriate for functions where there’s a high chance that the same input values will be used regularly. So Memoization may not be ideal for infrequently called or fast executing functions.

Third-party libraries for Memoization

You can use following third party libraries to implement Memoization:

References

Followings are some resources to help you out:

Conclusion

Memoization is a form of caching which gives performance improvements where a function is called many times with the same input. Applying Memoization will help you to write performant and robust code. But you have to be careful about not implementing it in an irrelevant scenario.

That's all for today. Thank you for reading, and don't forget to connect on LinkedIn or Twitter

If you have any questions or thoughts, please leave a comment!?