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
Advanced cache control features including manual cache manipulation, automatic expiration with pre-fetching, LRU-based size limiting, and reference counting for sophisticated memory management and performance optimization.
Direct manipulation of cache entries for fine-grained control over cached results.
/**
* Delete cached result for specific arguments
* @param {...any} args - Arguments to delete from cache (same as function arguments)
*/
memoizedFunction.delete(...args);
/**
* Clear all cached results
*/
memoizedFunction.clear();
/**
* Get cached value without triggering function execution
* @param {...any} args - Arguments to lookup
* @returns {any} Cached value or undefined if not cached
*/
memoizedFunction._get(...args);
/**
* Check if arguments have a cached result
* @param {...any} args - Arguments to check
* @returns {boolean} True if cached result exists
*/
memoizedFunction._has(...args);Usage Examples:
const memoize = require("memoizee");
function expensiveCalculation(x, y) {
console.log(`Computing ${x} * ${y}`);
return x * y;
}
const memoized = memoize(expensiveCalculation);
// Cache some results
memoized(5, 10); // "Computing 5 * 10", returns 50
memoized(3, 7); // "Computing 3 * 7", returns 21
// Check cache status
console.log(memoized._has(5, 10)); // true
console.log(memoized._has(2, 4)); // false
// Get cached value without execution
console.log(memoized._get(5, 10)); // 50 (no console output)
console.log(memoized._get(2, 4)); // undefined
// Delete specific cache entry
memoized.delete(5, 10);
console.log(memoized._has(5, 10)); // false
// Clear all cache
memoized.clear();
console.log(memoized._has(3, 7)); // falseAutomatically expire cache entries after a specified time period with optional pre-fetching.
/**
* Configure cache expiration
* @param {number} maxAge - Time to live in milliseconds
* @param {boolean|number} preFetch - Pre-fetch configuration
*/
const options = {
maxAge: number, // TTL in milliseconds
preFetch: boolean | number // Pre-fetch ratio (0-1) or boolean
};Usage Examples:
// Basic cache expiration
const memoizedWithTTL = memoize(fetchData, {
maxAge: 60000 // Cache for 1 minute
});
memoizedWithTTL("key"); // Fetches data
// ... 30 seconds later
memoizedWithTTL("key"); // Returns cached result
// ... 70 seconds after first call
memoizedWithTTL("key"); // Cache expired, fetches data again
// Pre-fetching to refresh cache before expiration
const memoizedWithPrefetch = memoize(fetchData, {
maxAge: 60000, // 1 minute TTL
preFetch: true // Default: refresh when 33% of TTL remains (20 seconds)
});
// Custom pre-fetch timing
const customPrefetch = memoize(fetchData, {
maxAge: 60000,
preFetch: 0.8 // Refresh when 80% of TTL elapsed (48 seconds)
});
// Pre-fetching with async functions
const asyncMemoized = memoize(asyncFunction, {
async: true,
maxAge: 30000, // 30 second TTL
preFetch: 0.5 // Refresh at 15 seconds
});Limit cache size using Least Recently Used (LRU) eviction policy to manage memory usage.
/**
* Configure cache size limit with LRU eviction
* @param {number} max - Maximum number of cache entries
*/
const options = {
max: number
};Usage Examples:
// Basic size limiting
const limitedCache = memoize(expensiveFunction, {
max: 100 // Keep only 100 most recent results
});
// Size limiting with disposal callback
const disposableCache = memoize(createResource, {
max: 50,
dispose: (resource) => {
// Clean up evicted resources
if (resource && resource.cleanup) {
resource.cleanup();
}
console.log("Resource disposed:", resource.id);
}
});
// Combined with time-based expiration
const hybridCache = memoize(fetchUserData, {
max: 200, // LRU limit
maxAge: 300000, // 5 minute TTL
dispose: (userData) => {
// Cleanup when evicted OR expired
if (userData.session) userData.session.close();
}
});Track cache entry usage and enable manual reference-based cache management.
/**
* Enable reference counting for cache entries
* @param {boolean} refCounter - Enable reference counting
*/
const options = {
refCounter: boolean
};
/**
* Reference counter methods available on memoized functions
*/
memoizedFunction.deleteRef(...args); // Decrement reference, delete if zero
memoizedFunction.getRefCount(...args); // Get current reference countUsage Examples:
const refMemoized = memoize(createExpensiveResource, {
refCounter: true
});
const resource1 = refMemoized("config-a"); // refs: 1
const resource2 = refMemoized("config-a"); // refs: 2 (cache hit)
const resource3 = refMemoized("config-a"); // refs: 3 (cache hit)
// Check reference count
console.log(refMemoized.getRefCount("config-a")); // 3
// Decrement references
console.log(refMemoized.deleteRef("config-a")); // false (refs: 2)
console.log(refMemoized.deleteRef("config-a")); // false (refs: 1)
console.log(refMemoized.deleteRef("config-a")); // true (refs: 0, deleted)
// Resource is now removed from cache
console.log(refMemoized.getRefCount("config-a")); // 0
// Next call will create new resource
const newResource = refMemoized("config-a"); // refs: 1 (new instance)Execute cleanup code when cache entries are removed or evicted.
/**
* Configure disposal callback for cache cleanup
* @param {Function} dispose - Callback executed when entries are removed
*/
const options = {
dispose: function(value) {
// Cleanup logic for cached value
}
};Usage Examples:
// File handle cleanup
const memoizedFileOp = memoize(openFile, {
max: 10, // Limit open files
dispose: (fileHandle) => {
fileHandle.close();
console.log("File closed:", fileHandle.path);
}
});
// Database connection cleanup
const memoizedDbQuery = memoize(createDbConnection, {
maxAge: 300000, // 5 minute connection TTL
dispose: (connection) => {
connection.close();
console.log("Database connection closed");
}
});
// Async disposal with promise functions
const promiseMemoized = memoize(asyncResourceFactory, {
promise: true,
max: 20,
dispose: (resource) => {
// Cleanup the resolved value from promises
if (resource && resource.cleanup) {
resource.cleanup();
}
}
});Advanced cache monitoring through event system for observability and debugging.
/**
* Cache event listeners
*/
memoizedFunction.on("set", (id, value, result) => {
// Called when value is cached
});
memoizedFunction.on("get", (id, args, context) => {
// Called when value is retrieved from cache
});
memoizedFunction.on("delete", (id, result) => {
// Called when cache entry is deleted
});
memoizedFunction.on("clear", (oldCache) => {
// Called when cache is cleared
});Usage Examples:
const monitoredMemoized = memoize(expensiveFunction, {
max: 100,
maxAge: 60000
});
// Monitor cache performance
let cacheHits = 0;
let cacheMisses = 0;
monitoredMemoized.on("get", () => {
cacheHits++;
});
monitoredMemoized.on("set", () => {
cacheMisses++;
});
// Log cache statistics periodically
setInterval(() => {
const total = cacheHits + cacheMisses;
const hitRate = total > 0 ? (cacheHits / total * 100).toFixed(2) : 0;
console.log(`Cache hit rate: ${hitRate}% (${cacheHits}/${total})`);
}, 10000);Pre-populate cache with frequently accessed data:
const memoized = memoize(expensiveFunction);
// Warm cache with common inputs
const commonInputs = [
[1, 2], [3, 4], [5, 6]
];
commonInputs.forEach(args => {
memoized(...args); // Populate cache
});Implement custom logic for when to cache results:
function conditionalMemoize(fn, shouldCache) {
const memoized = memoize(fn);
const original = memoized;
return function(...args) {
if (shouldCache(...args)) {
return original(...args); // Use memoized version
} else {
return fn(...args); // Call original function
}
};
}
const selectiveMemoized = conditionalMemoize(
expensiveFunction,
(x, y) => x > 10 && y > 10 // Only cache for large inputs
);Implement multi-level caching strategies:
// L1: Fast, small cache
const l1Cache = memoize(expensiveFunction, {
max: 50,
primitive: true
});
// L2: Slower, larger cache with TTL
const l2Cache = memoize(expensiveFunction, {
max: 500,
maxAge: 300000
});
function hierarchicalCache(...args) {
// Try L1 first
if (l1Cache._has(...args)) {
return l1Cache(...args);
}
// Try L2, promote to L1
const result = l2Cache(...args);
l1Cache(...args); // Store in L1
return result;
}