Examples can be found in my GitHub repository.
Table of contents
Open Table of contents
Introduction
In this blog post, we will explore the concept of memoization and how it can be used to optimize code performance. We will discuss the benefits of memoization and how it can be implemented in JavaScript applications to improve speed and efficiency.
What is memoization?
Memoization is a technique used to optimize the performance of functions by caching the results of expensive computations. When a function is memoized, the results of its computations are stored in a cache, allowing subsequent calls to the function with the same inputs to return the cached result instead of re-computing it. This can greatly improve the speed and efficiency of the function, especially when it is called with the same inputs multiple times.
How does memoization work?
When a function is memoized, the results of its computations are stored in a cache. The cache is typically implemented as a key-value store, where the inputs to the function are used as keys and the results of the computations are stored as values. When the function is called with a set of inputs, the cache is checked to see if the result for those inputs is already stored. If it is, the cached result is returned. If not, the function is called to compute the result, which is then stored in the cache for future use.
Example of memoization in JavaScript
Take an example of a search function that takes a query string as an input, calls an API to fetch search results, and returns the results. If the search function is called with the same query string multiple times, the results of the API call can be memoized to avoid redundant API calls and improve the performance of the function.
function fetchData({ query }: FetchDataParams): Promise<Location[]> {
return new Promise<Location[]>((resolve) => {
if (query.length) {
const fromCache = getFromCache(query) as Location[];
if (fromCache) {
resolve(fromCache);
return;
}
getLocation(query).then((data) => {
addToCache(query, data.results);
resolve(data.results);
});
}
});
}
In this example, the fetchData
function fetches location data from an API based on a query string. If the results for a particular query are already stored in the cache, they are returned using the getFromCache
function. If not, the API is called to fetch the results, which are then stored in the cache using the addToCache
function. Try searching for the same movie title multiple times to see the performance improvement.
Here is a simple implementation of the cache:
const cache = new Map<string, any>();
function getFromCache(key: string) {
return cache.get(key);
}
function addToCache(key: string, value: any) {
cache.set(key, value);
}
Benefits of memoization
Memoization can provide several benefits to JavaScript applications, including:
-
Improved performance: By caching the results of expensive computations, memoization can greatly improve the speed and efficiency of functions, especially when they are called with the same inputs multiple times.
-
Reduced API calls: Memoization can help reduce the number of API calls made by caching the results of previous calls and returning them when the same inputs are provided.
-
Reduced memory usage: Memoization can help reduce memory usage by storing the results of computations in a cache, allowing them to be reused instead of recomputed.
-
Simplified code: Memoization can simplify the code by removing the need to recompute the results of expensive computations, making the code easier to read and maintain.
Implementing memoization in React
useMemo hook
In a React application, memoization can be implemented using the useMemo
hook to cache the results of expensive computations. The useMemo
hook takes a function and an array of dependencies as arguments and returns the memoized result of the function. If the dependencies change, the function is called to recompute the result, which is then stored in the cache for future use.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
In this example, the computeExpensiveValue
function is called with the inputs a
and b
, and the result is memoized using the useMemo
hook. If a
or b
change, the function is called to recompute the result, which is then stored in the cache for future use.
useCallback hook
The useCallback
hook can also be used to memoize functions in a React application. The useCallback
hook takes a function and an array of dependencies as arguments and returns a memoized version of the function. If the dependencies change, the function is called to recompute the result, which is then stored in the cache for future use.
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
In this example, the doSomething
function is memoized using the useCallback
hook. If a
or b
change, the function is called to recompute the result, which is then stored in the cache for future use.
Difference between useMemo and useCallback
The useMemo
and useCallback
hooks are similar in that they both memoize the results of functions. However, they are used for different purposes:
-
useMemo
is used to memoize the result of an expensive computation and is typically used to optimize the performance of a value. -
useCallback
is used to memoize a function and is typically used to optimize the performance of a callback.
Conclusion
Memoization is a powerful technique for optimizing the performance of functions by caching the results of expensive computations. In JavaScript applications, memoization can greatly improve the speed and efficiency of functions, especially when they are called with the same inputs multiple times. By using the useMemo
and useCallback
hooks in a React application, memoization can be implemented to improve the performance of values and callbacks, making the code faster and more efficient.