JSPM

  • Created
  • Published
  • Downloads 293158
  • Score
    100M100P100Q162593F
  • License MIT

Blazing fast memoization based on all parameters passed

Package Exports

  • moize
  • moize/lib/utils

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (moize) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

moize

moize is a blazing fast implementation of memoization in JavaScript that supports all types of arguments, while offering flexibility in its implementation. It has no dependencies, and is less than 2kb when minified and gzipped.

Table of contents

Installation

$ npm i moize --save

Usage

import moize from 'moize';

const method = (a, b) => {
  return a + b;
};

const memoized = moize(method);

memoized(2, 4); // 6
memoized(2, 4); // 6, pulled from cache

All parameter types are supported, including circular objects, functions, etc. You can even memoize functional React components based on their props + context combination!

Advanced usage

moize also accepts an object of options as the second parameter. The full shape of these options:

{
  cache: Map|Object, // custom cache implementation
  isPromise: boolean, // is the result a promise
  maxAge: number, // amount of time in milliseconds before the cache will expire
  maxArgs: number, // maximum number of arguments to use as key for caching
  maxSize: number, // maximum size of cache for this method
  serializer: Function // method to serialize the arguments to build a unique cache key
}

cache defaults to new Map()

The default cache implementation is highly performant, however if you would like then you can pass in a custom cache implementation. The only requirements for the cache implementation is that it matches the relevant Map API methods:

  • delete
  • get
  • has
  • set

If you want to have direct cache management using moize, the following methods must also be provided:

  • clear
  • forEach
const cache = {
  delete(key) {
    delete this[key];
  },
  get(key) {
    return this[key];
  },
  has(key) {
    return this.hasOwnProperty[key];
  },
  set(key, value) {
    this[key] = value;
    
    return this;
  }
};
const fn = (item) => {
  return item;
};

const memoized = moize(fn, {
  cache
});

isPromise defaults to false

Is the computed value in the function a Promise, and should we cache the resolved value from that Promise.

const fn = async (item) => {
  return await item;
};

const memoized = moize(fn, {
  isPromise: true
});

maxAge defaults to Infinity

The maximum amount of time in milliseconds that you want a computed value to be stored in cache for this method.

const fn = (item) => {
  return item;
};

const memoized = moize(fn, {
  maxAge: 1000 * 60 * 5 // five minutes
});

maxArgs defaults to the length of arguments passed to the method

The maximum number of arguments used in creating the key for the cache.

const fn = (item1, item2, item3) => {
  return item1 + item2 + item3;
};

const memoized = moize(fn, {
  maxArgs: 2
});

maxSize defaults to Infinity

The maximum size of the cache you want stored in cache for this method. Clearance of the cache once the maxSize is reached is on a Least Recently Used basis.

const fn = (item) => {
  return item;
};

const memoized = moize(fn, {
  maxSize: 5
});

serializer defaults to serializeArguments in utils.js

The default seralizer method is highly performant, and covers a number of edge cases (recursive objects, for example), however if you want to provide a custom one you may. The value returned from the function must be a valid value of keys for a Map.

const serializer = (args) => {
  return JSON.stringify(args[0]);
};

const memoized = moize(fn, {
  serializer
});

Direct cache manipulation

There are a couple of methods provided on the memoized function which allow for programmatic manipulation of the cache:

clear()

This will clear all values in the cache, resetting it to a default state.

const memoized = moize((item) => {
  return item;
});

memoized.clear();

delete(key)

This will delete the provided key from cache.

const memoized = moize((item) => {
  return item;
});

memoized('foo');

memoized.delete('foo');

keys()

This will return a list of the current keys in cache.

const memoized = moize((item) => {
  return item;
});

memoized('foo');

const keys = memoized.keys(); // ['foo']

Benchmarks

All values provided are the number of operations per second (ops/sec) calculated by the Benchmark suite. Note that underscore, lodash, and ramda do not support mulitple-parameter memoization, so they are not included in those benchmarks. Each benchmark was performed using the default configuration of the library.

Single parameter image

underscore lodash ramda memoizee fast-memoize addy-osmani memoizerific iMemoized moize
5,998,566 6,402,406 242,619 4,405,116 6,344,116 1,945,595 1,125,026 11,704,638 10,037573

Multiple primitive parameters image

memoizee fast-memoize addy-osmani memoizerific iMemoized moize
3,088,475 274,799 1,042,220 747,047 3,094,359 3,251,022

Multiple complex parameters image

memoizee fast-memoize addy-osmani memoizerific iMemoized moize
3,475 222,977 479,436 31,704 40,044 650,998

Browser support

  • Chrome (all versions)
  • Firefox (all versions)
  • Opera 15+
  • Edge (all versions)
  • IE 9+
  • Safari 6+

Theoretically the support should go back even farther, these are just the environments that I have tested.

Development

Standard stuff, clone the repo and npm install dependencies. The npm scripts available:

  • build => run webpack to build development dist file with NODE_ENV=development
  • build:minifed => run webpack to build production dist file with NODE_ENV=production
  • dev => run webpack dev server to run example app (playground!)
  • dist => runs build and build-minified
  • docs => builds the docs via jsdoc
  • lint => run ESLint against all files in the src folder
  • prepublish => runs compile-for-publish
  • prepublish:compile => run lint, test, transpile, dist
  • test => run AVA test functions with NODE_ENV=test
  • test:coverage => run test but with nyc for coverage checker
  • test:watch => run test, but with persistent watcher
  • transpile => run babel against all files in src to create files in lib