Constraints of Lodash Default Map Cache
Lodash utilizes an internal caching mechanism for its memoization
utilities, defaulting to a Map-based implementation when
ES6 is available. While this default cache provides fast lookups and
basic functionality out of the box, it comes with specific operational
constraints regarding argument resolution, memory management, garbage
collection, and key comparison that developers must manage to prevent
performance degradation and memory leaks.
1. Single-Argument Key Resolution by Default
The most common constraint encountered with Lodash’s memoization
(_.memoize) is its key generation strategy. By default,
Lodash only uses the first argument passed to the memoized function as
the cache key:
const add = (a, b) => a + b;
const memoizedAdd = _.memoize(add);
memoizedAdd(2, 3); // Evaluates add(2, 3) -> 5
memoizedAdd(2, 5); // Returns cached 5 because it only evaluated the first argument (2)To use multiple arguments as a compound key, you must provide an
explicit resolver function that serializes or combines all
arguments.
2. Unbounded Growth and Lack of Eviction Policies
The default cache does not enforce a maximum size limit, nor does it implement an eviction strategy such as Least Recently Used (LRU), First In First Out (FIFO), or Time To Live (TTL) expiration.
Every unique key passed to the memoized function remains in memory
indefinitely unless the cache is manually cleared. In long-running
processes, such as Node.js servers, functions called with a high
cardinality of unique arguments will continuously consume memory,
eventually leading to OutOfMemory errors.
3. Strong References and Garbage Collection
The default cache holds strong references to both the keys and the
cached return values. Because it does not use a WeakMap,
objects used as keys will not be eligible for garbage collection even if
all other external references to them have been destroyed.
If you pass large objects or DOM nodes as keys, they will remain retained in the cache indefinitely, preventing memory reclamation.
4. Reference Equality for Non-Primitive Keys
Lodash’s Map cache uses the SameValueZero
algorithm for key comparison (identical to standard JavaScript
Map behavior).
When passing objects or arrays as keys without a custom resolver:
- Lookups evaluate identity by reference, not structural equality.
- Passing two distinct objects with identical properties
(
{ id: 1 }and{ id: 1 }) results in two separate cache entries. - Re-evaluations occur whenever an object literal or reconstructed object is passed, defeating the memoization logic.
5. Overriding Constraints
To address these limitations, Lodash allows you to replace
_.memoize.Cache globally or instantiate a customized cache
per function call:
- For compound arguments: Pass a custom resolver
function:
_.memoize(fn, (...args) => JSON.stringify(args)). - For size limits and TTL: Replace the default cache
constructor with an LRU cache implementation that conforms to the
Mapinterface (has,get,set,delete, andclearmethods).