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:
- JavaScript Fundamentals
- Closure
- Pure Function
- Higher-Order Function
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
In case if 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:
Invocations | Time Taken |
---|---|
First | 9.331ms |
Second | 2.336ms |
Third | 1.397ms |
Fourth | 0.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:
Demo Output:
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 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
cache
object is containing all the inputs only once.For example, We have inputted value 4 multiple times but it only storing it once. If the current inputted value is in the cache then it simply returns 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:
Result:
Invocations | Time Taken |
---|---|
First | 7.741ms |
Second | 0.056ms |
Third | 0.52ms |
Fourth | 0.045ms |
Normal function vs Memoized Function:
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 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:
- Memoization
- Closure
- Pure Function
- Higher-Order Functions
- console.time() / console.timeEnd()
- Memoization in React
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!?
Top comments (0)