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
Specialized memoization for Node.js callback-style functions and promise-returning functions. Handles error cases, prevents caching of failed operations, and supports multiple promise handling modes for robust asynchronous operation caching.
Memoization for Node.js style callback functions where the last parameter is a callback with (error, result) signature.
/**
* Enable memoization for Node.js callback-style async functions
* @param {boolean} async - Enable async callback handling
*/
const options = {
async: boolean
};Usage Examples:
const memoize = require("memoizee");
const fs = require("fs");
// Memoize file reading operations
const memoizedReadFile = memoize(fs.readFile, { async: true });
// First call - reads from disk
memoizedReadFile("./config.json", "utf8", (err, data) => {
if (err) console.error(err);
else console.log("File loaded:", data);
});
// Second call - returns cached result
memoizedReadFile("./config.json", "utf8", (err, data) => {
console.log("From cache:", data);
});
// Custom async function
function fetchUserData(userId, callback) {
setTimeout(() => {
if (userId === "invalid") {
callback(new Error("Invalid user ID"));
} else {
callback(null, { id: userId, name: `User ${userId}` });
}
}, 100);
}
const memoizedFetch = memoize(fetchUserData, { async: true });
memoizedFetch("123", (err, user) => {
console.log("User:", user); // Cached after first call
});Memoization for functions that return promises, with configurable promise handling modes and error management.
/**
* Enable memoization for promise-returning functions
* @param {boolean|string} promise - Enable promise handling with optional mode
*/
const options = {
promise: true | "then" | "then:finally" | "done" | "done:finally"
};Promise Handling Modes:
true or "then" (default): Uses .then() for promise resolution"then:finally": Uses .then() and .finally() for promise resolution"done": Uses .done() method (requires promise library support)"done:finally": Uses both .done() and .finally() methodsUsage Examples:
const memoize = require("memoizee");
// Basic promise memoization
async function fetchData(url) {
const response = await fetch(url);
return response.json();
}
const memoizedFetch = memoize(fetchData, { promise: true });
// First call - makes HTTP request
memoizedFetch("https://api.example.com/data")
.then(data => console.log("Fetched:", data));
// Second call - returns cached promise result
memoizedFetch("https://api.example.com/data")
.then(data => console.log("Cached:", data));
// With custom promise mode
const memoizedWithDone = memoize(fetchData, { promise: "done" });
// Error handling - failed promises are not cached
async function failingFunction(shouldFail) {
if (shouldFail) {
throw new Error("Operation failed");
}
return "Success";
}
const memoizedFailing = memoize(failingFunction, { promise: true });
memoizedFailing(true)
.catch(err => console.log("Error not cached"));
memoizedFailing(false)
.then(result => console.log("Success cached:", result));Using async memoization with other memoization features like cache expiration and size limits.
/**
* Combine async support with other memoization options
*/
const combinedOptions = {
async: boolean, // or promise: boolean|string
maxAge: number, // Cache expiration in milliseconds
max: number, // Maximum cache entries
preFetch: boolean // Pre-fetch before expiration
};Usage Examples:
// Async with cache expiration
const memoizedWithTTL = memoize(asyncFunction, {
async: true,
maxAge: 60000, // 1 minute TTL
preFetch: true // Refresh cache before expiration
});
// Promise with size limit
const memoizedPromiseWithLimit = memoize(promiseFunction, {
promise: true,
max: 50, // Keep only 50 cached results
dispose: (result) => {
// Cleanup when entries are evicted
if (result && result.cleanup) result.cleanup();
}
});
// Async with custom normalizer for object arguments
const memoizedAsyncNormalized = memoize(asyncDbQuery, {
async: true,
normalizer: (args) => JSON.stringify(args[0]) // First arg is query object
});Both async and promise modes automatically exclude failed operations from the cache:
const memoize = require("memoizee");
// Callback-style: errors are not cached
const memoizedAsync = memoize((id, callback) => {
if (id === "fail") {
callback(new Error("Failed"));
} else {
callback(null, `Result for ${id}`);
}
}, { async: true });
// Promise-style: rejections are not cached
const memoizedPromise = memoize(async (id) => {
if (id === "fail") {
throw new Error("Failed");
}
return `Result for ${id}`;
}, { promise: true });Async memoized functions emit special events for monitoring:
/**
* Async-specific cache events
*/
memoizedFunction.on("setasync", (id, callbackCount) => {
// Called when async result is cached
});
memoizedFunction.on("getasync", (id, args, context) => {
// Called when async result is retrieved from cache
});
memoizedFunction.on("deleteasync", (id, resultArray) => {
// Called when async cache entry is deleted
});
memoizedFunction.on("clearasync", (cache) => {
// Called when async cache is cleared
});Multiple concurrent calls with same arguments will be deduplicated:
const memoizedFetch = memoize(fetchData, { promise: true });
// These three calls will result in only one actual fetch
const promise1 = memoizedFetch("same-url");
const promise2 = memoizedFetch("same-url");
const promise3 = memoizedFetch("same-url");
// All three promises will resolve with the same result
Promise.all([promise1, promise2, promise3])
.then(results => {
// results[0] === results[1] === results[2]
});Automatically refresh cache entries before they expire:
const memoizedWithPrefetch = memoize(asyncFunction, {
async: true,
maxAge: 60000, // 1 minute expiration
preFetch: 0.8 // Start refresh when 20% of TTL remains
});
// Cache will be refreshed in background when accessed near expirationFor promise libraries that implement .done() method:
const Bluebird = require("bluebird");
function promiseFunction() {
return new Bluebird((resolve) => {
setTimeout(() => resolve("result"), 100);
});
}
const memoized = memoize(promiseFunction, {
promise: "done" // Uses Bluebird's .done() method
});Async caching may use additional memory for managing pending operations:
// Use size limits for async operations with high concurrency
const memoized = memoize(asyncOp, {
async: true,
max: 100, // Limit concurrent + cached operations
maxAge: 30000 // Clean up old entries
});"then" (default): Most compatible, but may suppress unhandled rejection warnings"done": Preserves error handling characteristics of promise library"done:finally": Best for libraries that support both, minimal side effects