CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-memoizee

Complete memoization/caching solution for JavaScript functions with support for any argument types, async/promise functions, cache expiration, and advanced cache management features

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

cache-management.mddocs/

Cache Management

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.

Capabilities

Manual Cache Control

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));  // false

Time-Based Cache Expiration

Automatically 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
});

LRU Cache Size Limiting

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();
  }
});

Reference Counting

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 count

Usage 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)

Disposal Callbacks

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();
    }
  }
});

Cache Events

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);

Advanced Cache Management Patterns

Cache Warming

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
});

Conditional Caching

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
);

Cache Hierarchies

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;
}

docs

async-functions.md

cache-management.md

function-memoization.md

index.md

method-memoization.md

profiling.md

weakmap-memoization.md

tile.json