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

async-functions.mddocs/

Asynchronous Functions

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.

Capabilities

Callback-Style Async Functions

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

Promise-Returning Functions

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() methods

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

Combined Async Configuration

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

Error Handling

Failed Operations Are Not Cached

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

Cache Events for Async Operations

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

Advanced Async Patterns

Concurrent Request Deduplication

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

Pre-fetching for Cache Refresh

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 expiration

Custom Promise Library Integration

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

Performance Considerations

Memory Usage with Async Caching

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

Choosing Promise Modes

  • "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

docs

async-functions.md

cache-management.md

function-memoization.md

index.md

method-memoization.md

profiling.md

weakmap-memoization.md

tile.json