npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chriscdn/memoize

v4.0.0

Published

Memoize a synchronous or asynchronous function.

Readme

@chriscdn/memoize

Memoize synchronous and asynchronous functions with an in-memory LRU cache.

Installing

Using npm:

npm install @chriscdn/memoize

Upgrading from v3 to v4

Breaking Change: As of v4, the shouldCache and ttl callbacks now accept an object containing args, value, and key. The refreshWhen callback now accepts an object containing args, value, key, and ttl.

Upgrading from v2 to v3

Breaking Change: As of v3, null return values are now cached.

Usage

import { Memoize, MemoizeAsync } from "@chriscdn/memoize";

Memoize is used to memoize synchronous functions. MemoizeAsync provides the same caching behavior for asynchronous functions, ensuring that concurrent calls with the same cache key only execute the underlying function once.

The cache is backed by quick-lru. Each call to Memoize or MemoizeAsync creates a new cache instance.

By default, the cache key is generated by calling JSON.stringify() on the function arguments. This behavior can be customized using the resolver option. Depending on your needs, you might consider a package such as canonicalize to create consistent cache keys regardless of object property order.

Functions that return undefined are not cached. Functions that return null are cached.

Example (Synchronous)

To memoize a function:

const _add = (x: number, y: number) => x + y;

const add = Memoize(_add);

The add function has the same interface as _add:

const result = add(5, 7);
// 12

You can also define the function in a single line:

const add = Memoize((x: number, y: number) => x + y);

Example (Asynchronous)

Memoizing an asynchronous function is similar:

const _add = async (x: number, y: number) => x + y;

const add = MemoizeAsync(_add);

const result = await add(5, 7);
// 12

MemoizeAsync also prevents concurrent calls with the same cache key from evaluating the underlying function more than once.

Options

Both Memoize and MemoizeAsync accept an options parameter to control cache behavior:

const add = Memoize(_add, options);

Available options and their defaults:

const options = {
  // The maximum number of items in the cache.
  maxSize: 1000,

  // The default maximum duration in milliseconds an item can remain in the cache.
  // A value returned by ttl overrides this.
  // undefined means that items do not expire due to time constraints.
  maxAge: undefined,

  // A synchronous function that determines whether the return value
  // should be added to the cache.
  shouldCache: ({
    value,
    key,
    args,
  }: {
    value: Return;
    key: string;
    args: Args;
  }) => true,

  // A synchronous function that determines the cache duration in milliseconds.
  //
  // A positive number uses that duration.
  // null or undefined uses the configured maxAge.
  // 0 or a negative number does not cache the value.
  ttl: ({ value, key, args }: { value: Return; key: string; args: Args }) =>
    null,

  // A synchronous function to generate a cache key.
  resolver: (...args) => JSON.stringify(args),
};

The shouldCache and ttl options receive an object containing the resolved value, cache key, and original function args.

The shouldCache option can be used to conditionally skip caching based on a resolved value.

The ttl option can be used to determine the cache duration based on the resolved value, cache key, and original function arguments.

The refreshWhen option is available only with MemoizeAsync:

const add = MemoizeAsync(_add, {
  refreshWhen: ({ ttl, args, value, key }) => ttl < 10000,
});

When refreshWhen returns true for a cached value, MemoizeAsync refreshes the value in the background while returning the existing cached value immediately. The callback receives the remaining ttl, the original args, the cached value, and the cache key.

Cache

The underlying quick-lru instance is accessible via the .cache property on the memoized function:

const add = Memoize(_add);

const result = add(5, 7);

console.log(add.cache.size === 1);
// true

The memoized function also exposes convenience methods for cache management:

// Remove a specific entry by arguments
add.delete(5, 7);

// Remove all entries
add.clear();

// Check whether an entry exists
add.has(5, 7);

// Get the remaining TTL in milliseconds
add.expiresIn(5, 7);

A value can also be added directly to the cache by passing the arguments array:

// make 1+1=3
add.set([1, 1], 3);

Class Methods

Class methods can also be memoized, but this requires overriding the method within the constructor. Ensure you bind the method to the instance to maintain the correct context. For example:

class AddClass {
  count: number = 0;

  constructor() {
    this.add = Memoize(this.add.bind(this));
  }

  add(x: number, y: number) {
    this.count += 1;

    return x + y;
  }
}

Each memoized method in each class instance maintains its own cache.

Tests

Run the tests using:

pnpm test

License

MIT