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 🙏

© 2024 – Pkg Stats / Ryan Hefner

functional-cache

v1.0.1

Published

Set of utility functions that let you decorate functions with cache

Downloads

38

Readme

Functional Cache Build Status Coverage Status npm version

Collection of helper functions that help you cache long running functions. Main goal of this library is to separate concerns between caching and business logic. It is inspired by functional programming memoization pattern, which let's you simply wrap function and optimize performance.

For example, you most probably written similar code:

const cache = new SomeCache();

function getBooks(type) {
  const cachedValue = cache.getValue(type);
  if (cachedValue) {
    return Promise.resolve(cachedValue);
  } else {
    return getBooksFromApi(type);
    cacheCalls;
  }
}

With this library you can simply write:

const cacheFactory = require('functional-cache');
const cache = cacheFactory.createNew();
const getBooks = cache.cacheCalls(getBooksFromApi);

Aim of this library is to keep original source code the same and encourage extracting all cache related logic to separate functions. With this in mind, these are more advanced features, that are supported:

Features

  • Cache eviction (with conditional eviction)
  • Custom cache key selection (built in helpers provided)
  • Conditional caching

Important

All wrapped functions should return promise/be async.

Custom cache providers

Cache creation

cache.createNew();

By default it will use in-memory cache with 1 minute TTL. This easily configured with second parameter, which takes instance of CacheProvider. Cache provider has the following interface:

  • set(key, value)
  • get(key)
  • remove(key)
  • removeAll()

CacheFactory on purpose does not have global configuration for TTL, namespacing and other details. They should be configured in cache provider. For example: new CacheFactory(new MyInMemoryCacheProvider({ttlSeconds: 60}))

Cache functions

cacheCalls(function, options)

Supported options:

  • keyGenerator - by default first argument of call is used, this lets customize key generation. It gets all original function arguments and has to result in cache key.
  • skipIf - used for conditional caching, takes all original function arguments and returns boolean value if value should be skipped from cache.

evictOnCall(function, options)

Removes value from cache on call based on cache key.

const cache = cacheFactory.createNew();
const getFavoriteBooks = cache.cacheCalls(getBooksFromApi);
const addToFavorites = cache.evictOnCall(addToFavoritesUsingApi);

Then:

// call API and write to cache
getFavoriteBooks('scifi');
// get from cache
getFavoriteBooks('scifi');
// removed from cache
addToFavorites('scifi', "Hitchhiker's Guide Through the Galaxy");
// call API again and write to cache
addToFavorites('scifi', "Hitchhiker's Guide Through the Galaxy");

addResultToCache(fn, options)

Similar to cacheCalls, but it never interferes with function execution, it just takes result of the function and puts into cache.

const cache = cacheFactory.createNew();
const getUserDetails = cache.cacheCalls(getUserFromDb);
const updateUserDetails = cache.addResultToCache(updateUserInDb);

Advanced usage

Customizing cache providers

cacheFactory.createNew function as first argument takes cache provider. By default it uses lru cache with default settings. You set any cache provider there, as long as it's adheres to defined interfaces.

If you want to use same LRU cache, but with different settings, you can do it this way:

const cacheFactory = require('functional-cache');
const { InMemoryCacheProvider } = require('functional-cache');
const cache = cacheFactory.createNew(
  new InMemoryCacheProvider({ maxAge: 1000 * 60 * 60 })
);

First parameter of InMemoryCacheProvider is options. Guide to available options is in original wrapped library lru cache

Key generators

Functional cache can wrap function with any amount of arguments. By default it uses first argument to pass along to cache key. However not always it can be used as a cache key. For this cacheCalls, evictOnCall and addResultCache functions has option keyGenerator it allows customizing cache key.

You can use one of predefined key generators like this:

const cacheFactory = require('functional-cache');
const { keyGenerators } = require('functional-cache');

// pick argument with index '1'
const options = { keyGenerator: keyGenerators.pickNthArgument(1) };
const getUserBooks = cache.cacheCalls(getUserBooksFromApi, options);

// user id will be used as a cache key
getUserBooks('some value', userId);

Key generator is just a function that gets all parameters from original call, so custom generator can be used:

const cacheFactory = require('functional-cache');

const pickUserName = (date, user) => user.username.toLowerCase();
const options = { keyGenerator: pickUserName };
const getUserBooks = cache.cacheCalls(getUserBooksFromApi, options);

// username converted to lower case will be used as a cache key
getUserBooks('some value', user);

Conditional caching/eviction

You might need to not cache certain values and use value directly from cache based on function arguments. Option skipIf allows that. Same as keyGenerator it gets all original call arguments. If returned value is true, then caching logic is skipped. For example:

const cacheFactory = require('functional-cache');

const options = { skipIf: (category, user) => user.role === 'ADMIN' };
const getFavoriteBooks = cache.cacheCalls(getFromApi, options);

// if user is admin, it will always get values from API
getUserBooks('sci-fi', user);