Complete memoization/caching solution for JavaScript functions with support for any argument types, async/promise functions, cache expiration, and advanced cache management features
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Memory-efficient memoization using WeakMap for garbage collection friendly caching when the first argument is expected to be an object. Cache entries are automatically garbage collected when objects are no longer referenced, preventing memory leaks in long-running applications.
Creates memoized functions that use WeakMap for automatic garbage collection of cache entries tied to object lifetimes.
/**
* Create WeakMap-based memoized function
* @param {Function} fn - Function to memoize (first argument must be an object)
* @param {Object} options - Configuration options (same as regular memoize)
* @returns {Function} WeakMap-based memoized function
*/
const weakMemoize = require("memoizee/weak");
const memoized = weakMemoize(fn, options);Usage Examples:
const weakMemoize = require("memoizee/weak");
// Object property analysis
function analyzeObject(obj) {
console.log("Analyzing object...");
return {
keys: Object.keys(obj).length,
hasNested: Object.values(obj).some(v => typeof v === 'object'),
firstKey: Object.keys(obj)[0]
};
}
const memoizedAnalyze = weakMemoize(analyzeObject);
const obj1 = { name: "Alice", age: 30 };
const obj2 = { name: "Bob", age: 25 };
memoizedAnalyze(obj1); // "Analyzing object...", computes result
memoizedAnalyze(obj1); // Returns cached result (no console output)
memoizedAnalyze(obj2); // "Analyzing object...", different object
// When obj1 goes out of scope and is garbage collected,
// its cache entry is automatically removedHandle functions that take an object as the first argument plus additional parameters.
/**
* WeakMap memoization with additional arguments beyond the object key
* The first argument becomes the WeakMap key, remaining args cached per object
*/
const memoized = weakMemoize(function(obj, ...otherArgs) {
// Function implementation
}, options);Usage Examples:
const weakMemoize = require("memoizee/weak");
// DOM element processing with options
function processElement(element, options) {
console.log("Processing element with options:", options);
return {
tagName: element.tagName,
id: element.id,
processed: true,
options: options
};
}
const memoizedProcess = weakMemoize(processElement);
const div1 = document.createElement('div');
const div2 = document.createElement('div');
// Same element, different options - separate cache entries per element
memoizedProcess(div1, { deep: true }); // Computes
memoizedProcess(div1, { deep: false }); // Computes (different options)
memoizedProcess(div1, { deep: true }); // Cache hit
// Different element
memoizedProcess(div2, { deep: true }); // Computes
// When DOM elements are removed from DOM and dereferenced,
// their cache entries are automatically cleaned upCombine WeakMap memoization with other memoization features like async support and cache management.
/**
* WeakMap memoization with advanced options
* All standard memoization options are supported except global cache operations
*/
const options = {
async: boolean, // Async function support
promise: boolean|string, // Promise function support
maxAge: number, // TTL per object (cleaned up with object)
max: number, // Max entries per object
refCounter: boolean, // Reference counting per object
dispose: Function, // Disposal callback
// Note: Global clear() is not available due to WeakMap limitations
};Usage Examples:
const weakMemoize = require("memoizee/weak");
// WeakMap with async support
const asyncWeakMemoized = weakMemoize(async function(obj, query) {
const response = await fetch(`/api/data/${obj.id}?q=${query}`);
return response.json();
}, {
promise: true,
maxAge: 60000 // Cache per object for 1 minute
});
// WeakMap with size limiting per object
const limitedWeakMemoized = weakMemoize(function(obj, operation) {
return performExpensiveOperation(obj, operation);
}, {
max: 10, // Max 10 cached results per object
dispose: (result) => {
if (result && result.cleanup) result.cleanup();
}
});
// User session example
class UserSession {
constructor(userId) {
this.userId = userId;
this.loginTime = Date.now();
}
}
const memoizedUserOperation = weakMemoize(function(session, operation) {
console.log(`Performing ${operation} for user ${session.userId}`);
return `${operation}_result_${session.userId}`;
}, {
maxAge: 300000 // 5 minute cache per session
});
const session1 = new UserSession("123");
memoizedUserOperation(session1, "getData"); // Computes
memoizedUserOperation(session1, "getData"); // Cache hit
// When session1 goes out of scope, its cache is automatically cleaned upRemove cache entries for specific objects and arguments.
/**
* Delete cache entry for specific object and remaining arguments
* @param {Object} obj - Object key for WeakMap
* @param {...any} args - Additional arguments to delete
*/
memoizedFunction.delete(obj, ...args);Usage Examples:
const weakMemoized = weakMemoize(processData);
const obj = { id: 1 };
weakMemoized(obj, "operation1");
weakMemoized(obj, "operation2");
// Delete specific operation for this object
weakMemoized.delete(obj, "operation1");
// Object still has cache for "operation2"
weakMemoized(obj, "operation2"); // Cache hit
weakMemoized(obj, "operation1"); // RecomputesUse reference counting with automatic cleanup when objects are garbage collected.
/**
* WeakMap with reference counting methods
*/
const options = { refCounter: true };
// Additional methods available when refCounter is enabled
memoizedFunction.deleteRef(obj, ...args); // Decrement reference
memoizedFunction.getRefCount(obj, ...args); // Get reference countUsage Examples:
const weakRefMemoized = weakMemoize(createResource, {
refCounter: true
});
const obj = { id: "resource-key" };
const resource1 = weakRefMemoized(obj, "config"); // refs: 1
const resource2 = weakRefMemoized(obj, "config"); // refs: 2 (cache hit)
console.log(weakRefMemoized.getRefCount(obj, "config")); // 2
weakRefMemoized.deleteRef(obj, "config"); // refs: 1
weakRefMemoized.deleteRef(obj, "config"); // refs: 0, entry deleted
// Next call creates new resource
const newResource = weakRefMemoized(obj, "config"); // refs: 1WeakMap memoization provides automatic memory cleanup when objects are no longer referenced:
function demonstrateGC() {
const weakMemoized = weakMemoize(expensiveOperation);
// Create objects and cache results
for (let i = 0; i < 1000; i++) {
const obj = { id: i, data: new Array(1000).fill(i) };
weakMemoized(obj, "process");
}
// All objects go out of scope here
// Cache entries will be garbage collected automatically
// No memory leak occurs
}
demonstrateGC();
// Memory is automatically cleaned up// Regular memoization - can cause memory leaks
const regularMemoized = memoize(function(obj, operation) {
return process(obj, operation);
});
// Objects are kept alive by the cache, preventing GC
const objects = [];
for (let i = 0; i < 1000; i++) {
const obj = { data: new Array(1000).fill(i) };
objects.push(obj);
regularMemoized(obj, "process");
}
// objects array and cache both hold references - memory not freed
// WeakMap memoization - automatic cleanup
const weakMemoized = weakMemoize(function(obj, operation) {
return process(obj, operation);
});
for (let i = 0; i < 1000; i++) {
const obj = { data: new Array(1000).fill(i) };
weakMemoized(obj, "process");
// obj goes out of scope, cache entry eligible for GC
}
// Memory can be freed by garbage collectorWeakMap-based memoization has some inherent limitations:
const weakMemoized = weakMemoize(someFunction);
// ❌ Cannot iterate over cached entries
// Object.keys(cache) is not possible
// ❌ Cannot get cache size
// cache.size is not available
// ❌ Cannot clear entire cache globally
// weakMemoized.clear() is not available
// ✅ Can delete entries for specific objects
weakMemoized.delete(specificObject, "arg");
// ✅ Automatic cleanup when objects are GC'dWeakMap memoization is ideal for:
// WeakMap has some performance characteristics to consider:
// ✅ Good: Object-based keys
const weakMemoized = weakMemoize(fn);
weakMemoized(objectKey, "operation");
// ❌ Avoid: Primitive first arguments (use regular memoize instead)
const regularMemoized = memoize(fn, { primitive: true });
regularMemoized("string-key", "operation"); // More efficient for primitives
// ✅ Good: When objects have natural lifetimes
function processUserSession(session, action) {
return weakMemoized(session, action); // Cleanup when session ends
}
// ✅ Good: Prevent memory leaks in long-running apps
const elementProcessor = weakMemoize(processElement);
elements.forEach(el => elementProcessor(el, options));
// Cache cleaned up when elements are removed from DOM