moize
moize
is a consistently blazing fast memoization library for JavaScript. It handles multiple parameters (including default values) without any additional configuration, and offers a large number of options to satisfy any number of potential use-cases.
$ npm i moize --save
Importing
ESM in browsers
import moize from 'moize';
ESM in NodeJS
import moize from 'moize/mjs/index.mjs';
CommonJS
const moize = require('moize');
Usage
import moize from 'moize';
const method = (a: number, b: number) => a + b;
const memoized = moize(method);
memoized(2, 4);
memoized(2, 4);
All parameter types are supported, including circular objects, functions, etc. There are also a number of shortcut methods to memoize for unique use-cases.
Configuration options
moize
optionally accepts an object of options as either the second parameter or as the first step in a curried function:
moize(fn, options);
moize(options)(fn);
The full shape of these options:
type Options = {
isDeepEqual: boolean;
isPromise: boolean;
isReact: boolean;
isSerialized: boolean;
isShallowEqual: boolean;
matchesArg: (cachedKeyArg: any, keyArg: any) => boolean;
matchesKey: (cachedKey: any[], key: any[]) => boolean;
maxAge: number;
maxArgs: number;
maxSize: number;
onCacheAdd: (
cache: moize.Cache,
options: moize.Options,
moized: (...args: any[]) => any
) => void;
onCacheChange: (
cache: moize.Cache,
options: moize.Options,
moized: (...args: any[]) => any
) => void;
onCacheHit: (
cache: moize.Cache,
options: moize.Options,
moized: (...args: any[]) => any
) => void;
onExpire: (key: any[]) => void;
profileName: string;
serializer: (key: any[]) => string;
transformArgs: (key: any[]) => any[];
updateCacheForKey: (key: any[]) => boolean;
updateExpire: boolean;
};
All default values can be found here.
isDeepEqual
defaults to false
Should deep equality be used to compare cache each key argument.
type Arg = {
one: {
nested: string;
};
two: string;
};
const fn = ({ one, two }: Arg) => [one, two];
const memoized = moize(fn, { isDeepEqual: true });
memoized({ one: { nested: 'one' }, two: 'two' });
memoized({ one: { nested: 'one' }, two: 'two' });
This is also available via the shortcut method of moize.deep
const memoized = moize.deep(fn);
isPromise
defaults to false
Is the computed value in the function a Promise
.
const fn = async (item: Promise<string>) => await item;
const memoized = moize(fn, { isPromise: true });
This is also available via the shortcut method of moize.promise
.
const memoized = -moize.promise(fn);
The Promise
itself will be stored in cache, so that cached returns will always maintain the Promise
contract. For common usage reasons, if the Promise
is rejected, the cache entry will be deleted.
isReact
defaults to false
Is the function passed a stateless functional React
component.
type Props = {
one: string;
two: number;
};
const Component = ({ one, two }: Props) => (
<div>
{one}: {two}
</div>
);
const MemoizedFoo = moize(Component, { isReact: true });
This is also available via the shortcut method of moize.react
.
const MemoizedFoo = moize.react(Component);
The method will do a shallow equal comparison of both props
and legacy context
of the component based on strict equality. If you want to do a deep equals comparison, set isDeepEqual
to true.
NOTE: This will memoize on each instance of the component passed, which is equivalent to PureComponent
or React.memo
. If you want to
memoize on all instances (which is how this option worked prior to version 6), use the following options:
const memoized = moize(Component, { isShallowEqual: true, maxArgs: 2 });
isSerialized
defaults to false
Serializes the parameters passed into a string and uses this as the key for cache comparison.
const fn = (mutableObject: { one: Record<string, any> }) =>
mutableObject.property;
const memoized = moize(fn, { isSerialized: true });
This is also available via the shortcut method of moize.serialize
.
const memoized = moize.serialize(fn);
If serialize
is combined with either maxArgs
or transformArgs
, the following order is used:
- limit by
maxArgs
(if applicable) - transform by
transformArgs
(if applicable) - serialize by
serializer
NOTE: This is much slower than the default key storage, and usually the same requirements can be meet with isDeepEqual
, so use at your discretion.
isShallowEqual
defaults to false
Should shallow equality be used to compare cache each key argument.
type Arg = {
one: string;
two: string;
};
const fn = ({ one, two }: Arg) => [one, two];
const memoized = moize(fn, { isShallowEqual: true });
memoized({ one: 'one', two: 'two' });
memoized({ one: 'one', two: 'two' });
This is also available via the shortcut method of moize.shallow
const memoized = moize.shallow(fn);
matchesArg
defaults to SameValueZero equality
Custom method used to compare equality of keys for cache purposes by comparing each argument.
type Arg = {
one: string;
two: string;
};
const fn = ({ one, two }: Arg) => [one, two];
const hasOneProperty = (cacheKeyArg: Arg, keyArg: Arg) =>
Object.keys(cacheKeyArg).length === 1 && Object.keys(keyArg).length === 1;
const memoized = moize(fn, { matchesArg: hasOneProperty });
memoized({ one: 'two' };
memoized({ two: 'three' });
This is also available via the shortcut method of moize.matchesArg
const memoized = moize.matchesArg(hasOneProperty)(fn);
NOTE: This comparison is used iteratively on each argument, rather than comparing the two keys as a whole. If you want to compare the key as a whole, you should use matchesKey
.
matchesKey
Custom method used to compare equality of keys for cache purposes by comparing the entire key.
type Arg = {
one: string;
two: string;
};
const fn = ({ one, two }: Arg) => [one, two];
const isFooEqualAndHasBar = (cacheKey: [Arg], key: [Arg]) =>
cacheKey[0].one === key[0].one &&
cacheKey[1].hasOwnProperty('two') &&
key[1].hasOwnProperty('two');
const memoized = moize(fn, { matchesKey: isFooEqualAndHasBar });
memoized({ one: 'two' }, { two: null });
memoized({ one: 'two' }, { two: 'three' });
This is also available via the shortcut method of moize.matchesKey
const memoized = moize.matchesKey(isFooEqualAndHasBar)(fn);
NOTE: This comparison uses the two keys as a whole, which is usually less performant than the matchArg
comparison used iteratively on each argument. Generally speaking you should use the matchArg
option for equality comparison.
maxAge
The maximum amount of time in milliseconds that you want a computed value to be stored in cache for this method.
const fn = (item: Record<string, any>) => item;
const MAX_AGE = 1000 * 60 * 5;
const memoized = moize(fn, { maxAge: MAX_AGE });
This is also available via the shortcut method of moize.maxAge
.
const memoized = moize.maxAge(MAX_AGE)(fn);
TIP: A common usage of this is in tandom with isPromise
for AJAX calls, and in that scenario the expected behavior is usually to have the maxAge
countdown begin upon resolution of the promise. If this is your intended use case, you should also apply the updateExpire
option.
maxArgs
The maximum number of arguments (starting from the first) used in creating the key for the cache.
const fn = (item1: string, item2: string, item3: string) =>
item1 + item2 + item3;
const memoized = moize(fn, { maxArgs: 2 });
memoize('one', 'two', 'three');
memoize('one', 'two', 'four');
This is also available via the shortcut method of moize.maxArgs
.
const memoized = moize.maxArgs(2)(fn);
If maxArgs
is combined with either serialize
or transformArgs
, the following order is used:
- limit by
maxArgs
- transform by
transformArgs
(if applicable) - serialize by
serializer
(if applicable)
maxSize
defaults to 1
The maximum number of values 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: string) => item;
const memoized = moize(fn, { maxSize: 5 });
This is also available via the shortcut method of moize.maxSize
.
const memoized = moize.maxSize(5)(fn);
onCacheAdd
Method to fire when an item has been added to cache. Receives the cache, options, and memoized function as a parameters.
const fn = (one: string, two: string) => [one, two];
const logCacheKeys = (
cache: Cache,
options: Options,
moized: Moized<typeof fn>
) => console.log(cache.keys);
const moized = moize(fn, { maxSize: 2, onCacheAdd: logCacheKeys });
moized('one', 'two');
moized('one', 'two');
moized('two', 'one');
moized('one', 'two');
NOTE: When combined with onCacheChange
, this method will always fire first.
onCacheChange
Method to fire when an item has been either added to cache, or existing cache was reordered based on a cache hit. Receives the cache, options, and memoized function as a parameters.
const fn = (one: string, two: string) => [one, two];
const logCacheKeys = (
cache: Cache,
options: Options,
moized: Moized<typeof fn>
) => console.log(cache.keys);
const moized = moize(fn, { maxSize: 2, onCacheChange: logCacheKeys });
moized('one', 'two');
moized('one', 'two');
moized('two', 'one');
moized('one', 'two');
NOTE: When combined with onCacheAdd
or onCacheHit
, this method will always fire last.
onCacheHit
Method to fire when an existing cache item is found. Receives the cache, options, and memoized function as a parameters.
const fn = (one: string, two: string) => [one, two];
const logCacheKeys = (
cache: Cache,
options: Options,
moized: Moized<typeof fn>
) => console.log(cache.keys);
const moized = moize(fn, { maxSize: 2, onCacheHit: logCacheKeys });
moized('one', 'two');
moized('one', 'two');
moized('two', 'one');
moized('one', 'two');
NOTE: When combined with onCacheChange
, this method will always fire first.
onExpire
A callback that is called when the cached entry expires.
const fn = (item: string) => item;
const logKey = (key: Key<string>) => console.log(key);
const memoized = moize(fn, { maxAge: 10000, onExpire: logKey });
If you return false
from this method, it will prevent the key's removal and refresh the expiration in the same vein as updateExpire
based on maxAge
:
const fn = (item: string) => item;
let expirationAttempts = 0;
const limitExpirationAttempts = (key: Key<string>) => {
expirationAttempts += 1;
return expirationAttempts < 2;
};
const memoized = moize(fn, {
maxAge: 10000,
onExpire: limitExpirationAttempts,
});
memoized('one');
NOTE: You must set a maxAge
for this option to take effect.
profileName
defaults to function name when it exists, or Anonymous {count}
otherwise
Name to use as unique identifier for the function when collecting statistics.
moize.collectStats();
const fn = (item: string) => item;
const memoized = moize(fn, { profileName: 'my fancy identity' });
This is also available via the shortcut method of moize.profile
.
const memoized = moize.profile('profile-name')(fn);
NOTE: You must be collecting statistics for this option to provide value, as it is the identifier used for statistics collection.
serializer
defaults to serializeArguments in utils.js
Method used in place of the internal serializer when serializing the parameters for cache key comparison. The function accepts a single argument, the Array
of args
, and must also return an Array
.
const fn = (one: string, two: string) => [one, two];
const customSerializer = (args: string[]) => [JSON.stringify(args[0])];
const memoized = moize(fn, {
isSerialized: true,
serializer,
});
This is also available via the shortcut method of moize.serializeWith
.
const memoized = moize.serializeWith(customSerializer)(fn);
NOTE: You must set isSerialized
for this option to take effect.
transformArgs
Transform the arguments passed before it is used as a key. The function accepts a single argument, the Array
of args
, and must also return an Array
.
const fn = (one: string | null, two: string | null, three: string | null) => [
two,
three,
];
const ignoreFirstArg = (args: (string | null)[]) => args.slice(1);
const moized = moize(fn, { transformArgs: ignoreFirstArg });
moize('one', 'two', 'three');
moize(null, 'two', 'three');
This is also available via the shortcut method of moize.transformArgs
.
const memoized = moize.transformArgs(argTransformer)(fn);
If transformArgs
is combined with either maxArgs
or serialize
, the following order is used:
- limit by
maxArgs
(if applicable) - transform by
transformArgs
- serialize by
serializer
(if applicable)
updateCacheForKey
If you want to update the cache for a given key instead of leverage the value currently stored in cache.
const fn = (item: string) => item;
let lastUpdate = Date.now();
const memoized = moize(fn, {
updateCacheForKey([item]: [string]) {
const now = Date.now();
const last = lastUpdated;
lastUpdate = now;
return last + 300000 < now;
},
});
memoized('one');
memoized('one');
memoized('one');
This is also available via the shortcut method of moize.updateCacheForKey
.
const memoized = moize.updateCacheForKey(shouldCacheUpdate)(fn);
updateExpire
When a maxAge
is set, clear the scheduled expiration of the key when that key is retrieved, setting a new expiration based on the most recent retrieval from cache.
const fn = (item: string) => item;
const MAX_AGE = 1000 * 60 * 5;
const memoized = moize(fn, { maxAge: MAX_AGE, updateExpire: true });
memoized('one');
setTimeout(() => {
memoized('one');
}, 1000 * 60);
Usage with shortcut methods
moize.deep
Pre-applies the isDeepEqual
option.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.deep(fn);
moize.infinite
Pre-applies the maxSize
option with Infinity
.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.infinite(fn);
NOTE: This mimics default behavior of moize
prior to version 6.
moize.matchesArg
Pre-applies the matchesArg
option as a curriable method.
import moize from 'moize';
const isEqualOrFoo = (cacheKeyArg: string, keyArg: string) =>
cacheKeyArg === keyArg || keyArg === 'one';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.matchesArg(isEqualOrFoo)(fn);
moize.matchesKey
Pre-applies the matchesKey
option as a curriable method.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
const isEqualOrHasFoo = (cacheKey: Key<string>, key: Key<string>) =>
key.every((keyArg, index) => keyArg === cacheKey[index]) ||
key.some((keyArg) => keyArg === 'one');
export default moize.matchesKey(isEqualOrHasFoo)(fn);
moize.maxAge
Pre-applies the maxAge
option as a curriable method.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.maxAge(5000)(fn);
moize.maxArgs
Pre-applies the maxArgs
option as a curriable method.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.maxArgs(1)(fn);
moize.maxSize
Pre-applies the maxSize
option as a curriable method.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.maxSize(5)(fn);
moize.profile
Pre-applies the profileName
option as a curriable method.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.profile('my fancy identity')(fn);
NOTE: You must be collecting statistics for this option to provide value, as it is the identifier used for statistics collection.
moize.promise
Pre-applies the isPromise
and updateExpire
options. The updateExpire
option does nothing if maxAge
is not also applied, but ensures that the expiration begins at the resolution of the promise rather than the instantiation of it.
import moize from 'moize';
const fn = async (one: string, two: Record<string, any>) =>
await someApiCall(one, two);
export default moize.promise(fn);
NOTE: If you do not want the promise to update its expiration when the cache is hit, then you should use the isPromise
option directly instead.
moize.react
Pre-applies the isReact
) option for memoizing functional components in React. Key
comparisons are based on a shallow equal comparison of both props and legacy context.
import moize from 'moize';
type Props = {
one: string;
two: number;
};
const Component = ({ one, two }: Props) => (
<div>
{one} {two}
</div>
);
export default moize.react(Component);
NOTE: This method will not operate with components made via the class
instantiation, as they do not offer the same referential transparency.
moize.serialize
Pre-applies the isSerialized
option.
import moize from 'moize';
const fn = (one: Record<string, any>, two: Record<string, any>) => ({
one,
two,
});
export default moize.serialize(fn);
NOTE: If you want to provide a custom serializer
, you should use moize.serializeWith
:
moize.serializeWith(customSerializer)(fn);
moize.serializeWith
Pre-applies the isSerialized
and serializer
options.
import moize from 'moize';
const fn = (one: Record<string, any>, two: Record<string, any>) => ({
one,
two,
});
export default moize.serializeWith(JSON.stringify)(fn);
NOTE: If you want to use the default serializer
, you should use moize.serialize
:
moize.serialize(customSerializer)(fn);
moize.shallow
Pre-applies the isShallowEqual
option.
import moize from 'moize';
const fn = (one: string, two: string) => `${one} ${two}`;
export default moize.shallow(fn);
moize.transformArgs
Pre-applies the transformArgs
option.
import moize from 'moize';
const fn = ([one, two]: string[]) => [`${one} ${two}`];
export default moize.transformArgs(fn);
moize.updateCacheForKey
Pre-applies the updateCacheForKey
option.
import moize from 'moize';
let lastUpdated = Date.now();
const fn = () => {
const now = Date.now();
const last = lastUpdated;
lastUpdate = now;
return last + 300000 < now;
};
export default moize.updateCacheForKey(fn);
useMoize hook
If you are using React 16.8+ and are using hooks, you can easily create a custom useMoize
hook for your project:
import { useRef } from 'react';
export function useMoize(fn, args, options) {
const moizedFnRef = useRef(moize(fn, options));
return moizedFnRef.current(...args);
}
Which can then be used as such:
import React from 'react';
import { useMoize } from './moize-hooks';
function MyComponent({ first, second, object }) {
const sum = useMoize((a, b) => a + b, [first, second]);
const deepSum = useMoize((obj) => obj.a + obj.b, [object], {
isDeepEqual: true,
});
return (
<div>
Sum of {first} and {second} is {sum}. Sum of {object.a} and{' '}
{object.b} is {deepSum}.
</div>
);
}
Naturally you can tweak as needed for your project (default options, option-specific hooks, etc).
NOTE: This is very similar to useCallback
built-in hook, with two main differences:
- There is a third parameter passed (the
options
passed to moize
) - The second argument array is the list of arguments passed to the memoized function
In both useCallback
and useMemo
, the array is a list of dependencies which determine whether the funciton is called. These can be different than the arguments, although in general practice they are equivalent. The decision to use them directly was both for this common use-case reasons, but also because the implementation complexity would have increased substantially if not.
Composition
Starting with version 2.3.0
, you can compose moize
methods. This will create a new memoized method with the original function that shallowly merges the options of the two setups. Example:
import moize from 'moize';
const Component = (props: Record<string, any>) => <div {...props} />;
const MemoizedFoo = moize.react(Component);
const LastFiveFoo = moize.maxSize(5)(MemoizedFoo);
You can also create an options-first curriable version of moize
if you only pass the options:
import moize from 'moize';
const limitedSerializedMoize = moize({ maxSize: 5, serialize: true });
const getWord = (bird) => `${bird} is the word`;
const moizedGetWord = limitedSerializedMoize(getWord);
You can also combine all of these options with moize.compose
to create moize
wrappers with pre-defined options.
import moize from 'moize';
const superLimitedReactMoize = moize.compose(
moize.react,
moize.maxSize(5),
moize.maxAge(5000)
);
Collecting statistics
As-of version 5, you can collect statistics of moize to determine if your cached methods are effective.
import moize from 'moize';
moize.collectStats();
const fn = (one: string, two: string) => [one, two];
const moized = moize(fn);
moized('one', 'two');
moized('one', 'two');
moized.getStats();
NOTE: It is recommended not to activate this in production, as it will have a performance decrease.
Stats methods
clearStats
Cear statistics on moize
d functions.
moize.clearStats();
moize.clearStats('profile-name');
collectStats
Set whether collecting statistics on moize
d functions.
moize.collectStats(true);
moize.collectStats();
moize.collectStats(false);
NOTE: If collecting statistics, it is recommended to provide a custom profileName
or use moize.profile()
for all memoized functions. This allows easier mapping of resulting statistics to their origin function when it has a common name or is anonymous.
getStats([profileName])
Get the statistics for a specific function, or globally.
moize.collectStats();
const fn = (one: string, two: string) => [one, two];
const moized = moize(fn);
const otherFn = (one: string[]) => one.slice(0, 1);
const otherMoized = moize(otherFn, { profileName: 'otherMoized' });
moized('one', 'two');
moized('one', 'two');
moized.getStats();
otherMoized(['three']);
moize.getStats('otherMoized');
moize.getStats();
Introspection
isCollectingStats
Are statistics being collected on memoization usage.
moize.collectStats(true);
moize.isCollectingStats();
moize.collectStats(false);
moize.isCollectingStats();
isMoized
Is the function passed a moized function.
const fn = () => {};
const moizedFn = moize(fn);
moize.isMoized(fn);
moize.isMoized(moizedFn);
Direct cache manipulation
The cache is available on the moize
d function as a property, and while it is not recommended to modify it directly, that option is available for edge cases.
cache
The shape of the cache
is as follows:
type Cache = {
keys: any[][];
size: number;
values: any[];
};
Regardless of how the key is transformed, it is always stored as an array (if the value returned is not an array, it is coalesced to one).
NOTE: The order of keys
and values
should always align, so be aware when manually manipulating the cache that you need to manually keep in sync any changes to those arrays.
cacheSnapshot
The cache
is mutated internally for performance reasons, so logging out the cache at a specific step in the workflow may not give you the information you need. As such, to help with debugging you can request the cacheSnapshot
, which has the same shape as the cache
but is a shallow clone of each property for persistence.
There are also convenience methods provided on the moize
d function which allow for programmatic manipulation of the cache.
add(key, value)
This will manually add the value at key in cache if key does not already exist. key should be an Array
of values, meant to reflect the arguments passed to the method.
const memoized = moize((item: string) => item: string);
memoized.add(['one'], 'two');
memoized('one');
NOTE: This will only add key
s that do not exist in the cache, and will do nothing if the key
already exists. If you want to update keys that already exist, use update
.
clear()
This will clear all values in the cache, resetting it to an empty state.
const memoized = moize((item: string) => item);
memoized.clear();
get(key)
Returns the value in cache if the key matches, else returns undefined
. key should be an Array
of values, meant to reflect the arguments passed to the method.
const memoized = moize((one: string, two: string) => [one, two);
memoized('one', 'two');
console.log(memoized.get(['one', 'two']));
console.log(memoized.get(['two', 'three']));
getStats()
Returns the statistics for the function.
moize.collectStats();
const memoized = moize((one: string, two: string) => [one, two);
memoized('one', 'two');
memoized('one', 'two');
console.log(memoized.getStats());
NOTE: You must be collecting statistics for this to be populated.
has(key)
This will return true
if a cache entry exists for the key passed, else will return false
. key should be an Array
of values, meant to reflect the arguments passed to the method.
const memoized = moize((one: string, two: string) => [one, two]);
memoized('one', 'two');
console.log(memoized.has(['one', 'two']));
console.log(memoized.has(['two', 'three']));
keys()
This will return a list of the current keys in cache
.
const memoized = moize.maxSize(2)((item: any) => item);
memoized('one');
memoized({ two: 'three' });
const keys = memoized.keys();
remove(key)
This will remove the provided key from cache. key should be an Array
of values, meant to reflect the arguments passed to the method.
const memoized = moize((item: { one: string }) => item);
const arg = { one: 'one' };
memoized(arg);
memoized.remove([arg]);
memoized(arg);
NOTE: This will only remove key
s that exist in the cache, and will do nothing if the key
does not exist.
update(key, value)
This will manually update the value at key in cache if key exists. key should be an Array
of values, meant to reflect the arguments passed to the method.
const memoized = moize((item: string) => item);
memoized.add(['one'], 'two');
memoized('one');
NOTE: This will only update key
s that exist in the cache, and will do nothing if the key
does not exist. If you want to add keys that do not already exist, use add
.
values()
This will return a list of the current values in cache
.
const memoized = moize.maxSize(2)((item: string | { two: string }) => ({
item,
}));
memoized('one');
memoized({ two: 'three' });
const values = memoized.values();
Benchmarks
All values provided are the number of operations per second calculated by the Benchmark suite, where a higher value is better. Each benchmark was performed using the default configuration of the library, with a fibonacci calculation based on a starting parameter of 35
, using single and multiple parameters with different object types. The results were averaged to determine overall speed across possible usage.
NOTE: lodash
, ramda
, and underscore
do not support mulitple-parameter memoization without use of a resolver
function. For consistency in comparison, each use the same resolver
that returns the result of JSON.stringify
on the arguments.
Name | Overall (average) | Single (average) | Multiple (average) | single primitive | single array | single object | multiple primitive | multiple array | multiple object |
---|
moize | 71,177,801 | 98,393,482 | 43,962,121 | 139,808,786 | 97,571,202 | 57,800,460 | 44,509,528 | 44,526,039 | 42,850,796 |
lru-memoize | 48,391,839 | 64,270,849 | 32,512,830 | 77,863,436 | 59,876,764 | 55,072,348 | 29,917,027 | 33,308,028 | 34,313,435 |
mem | 42,348,320 | 83,158,473 | 1,538,166 | 128,731,510 | 73,473,478 | 47,270,433 | 2,012,120 | 1,565,253 | 1,037,126 |
fast-memoize | 33,145,713 | 64,942,152 | 1,349,274 | 190,677,799 | 2,149,467 | 1,999,192 | 1,718,229 | 1,297,911 | 1,031,683 |
lodash | 25,700,293 | 49,941,573 | 1,459,013 | 67,513,655 | 48,874,559 | 33,436,506 | 1,861,982 | 1,402,532 | 1,112,527 |
memoizee | 21,546,499 | 27,447,855 | 15,645,143 | 29,701,124 | 27,294,197 | 25,348,244 | 15,359,792 | 15,855,421 | 15,720,217 |
ramda | 18,804,380 | 35,919,033 | 1,689,727 | 101,557,928 | 1,895,956 | 4,303,215 | 2,305,025 | 1,597,131 | 1,167,025 |
memoizerific | 6,745,058 | 7,382,030 | 6,108,086 | 8,488,885 | 6,427,832 | 7,229,375 | 5,772,461 | 6,278,344 | 6,273,453 |
underscore | 6,701,695 | 11,698,265 | 1,705,126 | 18,249,423 | 4,695,658 | 12,149,714 | 2,310,412 | 1,630,769 | 1,174,197 |
addy-osmani | 4,926,732 | 6,370,152 | 3,483,311 | 12,506,809 | 3,568,399 | 3,035,249 | 6,898,542 | 2,009,089 | 1,542,304 |
Filesize
moize
is fairly small (~3.86KB when minified and gzipped), however it provides a large number of configuration options to satisfy a number of edge cases. If filesize is a concern, you may consider using micro-memoize
. This is the memoization library that powers moize
under-the-hood, and will handle most common use cases at 1/4 the size of moize
.
Browser support
- Chrome (all versions)
- Firefox (all versions)
- Edge (all versions)
- Opera 15+
- IE 9+
- Safari 6+
- iOS 8+
- Android 4+
Development
Standard stuff, clone the repo and npm install
dependencies. The npm scripts available:
benchmark
=> run the benchmark suite pitting moize
against other libraries in common use-casesbenchmark:alternative
=> run the benchmark suite for alternative forms of cachingbenchmark:array
=> run the benchmark suite for memoized methods using single and multiple array
parametersbenchmark:object
=> run the benchmark suite for memoized methods using single and multiple object
parametersbenchmark:primitive
=> run the benchmark suite for memoized methods using single and multiple object
parametersbenchmark:react
=> run the benchmark suite for memoized React componentsbuild
=> run rollup to build the distributed files in dist
clean:dist
=> run rimraf
on the dist
folderclean:docs
=> run rimraf
on the docs
folderclean:mjs
=> run rimraf
on the mjs
foldercopy:mjs
=> run clean:mjs
and the es-to-mjs
scriptcopy:types
=> copy internal types to be available for consumerdev
=> run webpack dev server to run example app (playground!)dist
=> runs clean:dist
and build
docs
=> runs clean:docs
and builds the docs via jsdoc
flow
=> runs flow check
on the files in src
lint
=> runs ESLint against all files in the src
folderlint:fix
=> runs lint
, fixing any errors if possibletest
=> run jest
test functions with NODE_ENV=test
test:coverage
=> run test
but with code coveragetest:watch
=> run test
, but with persistent watchertypecheck
=> run tsc
against source code to validate TypeScript