Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nano-memoize

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nano-memoize - npm Package Compare versions

Comparing version 1.1.1 to 1.1.2

benchmark/micro-memoize.min.js

0

benchmark/addy-osmani.js

@@ -0,0 +0,0 @@ /*

42

browser/nano-memoize.js

@@ -1,6 +0,5 @@

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function() {
"use strict";
const vrgs = f => {
const s = f+"",
var vrgs = f => {
var s = f+"",
i = s.indexOf("...");

@@ -12,7 +11,7 @@ return i>=0 && i<s.indexOf(")" || s.indexOf("arguments")>=0);

equals, // equality tester, will force use of slower multiarg approach even for single arg functions
maxAge, // max cache age is ms, set higher than 0 if you want automatic clearing
maxAge, // max cache age is ms, set > 0 && < Infinity if you want automatic clearing
maxArgs, // max args to use for signature
vargs = vrgs(fn) // set to true if function may have variable or beyond-signature arguments, default if best attempt at infering
}={}) => {
const s = Object.create(null), // single arg function key/value cache
var s = Object.create(null), // single arg function key/value cache
k = [], // multiple arg function arg key cache

@@ -24,5 +23,5 @@ v = [], // multiple arg function result cache

},maxAge),
I = Infinity;
let f, // memoized function to return
u; // flag indicating a unary arg function is in use
I = Infinity,
f, // memoized function to return
u; // flag indicating a unary arg function is in use for clear operation
if(fn.length===1 && !equals && !vargs) {

@@ -38,7 +37,7 @@ // for single argument functions, just use a JS object key look-up

// strings must be serialized because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const t = typeof a,
var t = typeof a,
key = t === "number" || t === "boolean" || (!p && t === "object") ? a : t === "string" ? JSON.stringify(t) : p(a);
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(!p && t==="object") {
let r;
var r;
return wm.m.get(key) || ((!c||c(key,wm.m)),wm.m.set(key,r = fn.call(this, a)),r);

@@ -52,3 +51,3 @@ }

wm,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
serializer

@@ -68,17 +67,10 @@ );

f = (function(f,k,v,e,c,m,...a) {
const l = m||a.length;
let i;
for(i=0;i<k.length;i++) { // an array of arrays of args, each array represents a call signature
let p = k[i];
if(p && p.length===a.length) {
for(let j=0;j<=l;j++) {
if(e ? !e(p[j],a[j]) : p[j]!==a[j]) break; // go to next call signature if args don't match
if(j===l) { // the args matched
if(v[i]!==undefined) return v[i];
}
}
var i,j,l = m||a.length; // use var, slightly smaller and faster for loops, and i needs more scope
for(i=0;i<k.length && v[i]!==undefined;i++) { // an array of arrays of args, each array represents a call signature
for(j=0;j<=l && (k[i][j]===a[j] || (e && e(k[i][j],a[j])));j++) { // compare each arg //if(p[j]!==a[j] && (!e || !e(p[j],a[j]))) break; // go to next call signature if args don't match
if(j===l) return v[i]; // the args matched
}
}
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(c) c(i,v);
!c||c(i,v);
return v[i] = fn.apply(this,k[i] = a);

@@ -91,3 +83,3 @@ }).bind(

equals,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
maxArgs

@@ -94,0 +86,0 @@ );

@@ -1,1 +0,1 @@

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){(function(){"use strict";const vrgs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)},nanomemoize=(fn,{serializer:serializer,equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=vrgs(fn)}={})=>{const s=Object.create(null),k=[],v=[],wm={m:new WeakMap},d=(key,c)=>setTimeout(()=>{c instanceof WeakMap?c.delete(key):delete c[key]},maxAge),I=Infinity;let f,u;if(fn.length===1&&!equals&&!vargs){f=function(f,s,wm,c,p,a){const t=typeof a,key=t==="number"||t==="boolean"||!p&&t==="object"?a:t==="string"?JSON.stringify(t):p(a);if(!p&&t==="object"){let r;return wm.m.get(key)||(!c||c(key,wm.m),wm.m.set(key,r=fn.call(this,a)),r)}return s[key]||(!c||c(key,s),s[key]=fn.call(this,a))}.bind(this,fn,s,wm,maxAge&&maxAge<I?d:0,serializer);u=1}else{f=function(f,k,v,e,c,m,...a){const l=m||a.length;let i;for(i=0;i<k.length;i++){let p=k[i];if(p&&p.length===a.length){for(let j=0;j<=l;j++){if(e?!e(p[j],a[j]):p[j]!==a[j])break;if(j===l){if(v[i]!==undefined)return v[i]}}}}if(c)c(i,v);return v[i]=fn.apply(this,k[i]=a)}.bind(this,fn,k,v,equals,maxAge&&maxAge<I?d:0,maxArgs)}f.clear=(_=>{Object.keys(s).forEach(k=>delete s[k]);wm.m=new WeakMap;k.length=0;v.length=0});f.keys=(_=>u?null:k.slice());f.values=(_=>u?null:v.slice());f.keyValues=(_=>u?{primitives:Object.assign({},s),objects:wm.m}:null);return f};if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this)},{}]},{},[1]);
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){(function(){var vrgs=f=>{var s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)},nanomemoize=(fn,{serializer:serializer,equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=vrgs(fn)}={})=>{var s=Object.create(null),k=[],v=[],wm={m:new WeakMap},d=(key,c)=>setTimeout(()=>{c instanceof WeakMap?c.delete(key):delete c[key]},maxAge),I=Infinity,f,u;if(fn.length===1&&!equals&&!vargs){f=function(f,s,wm,c,p,a){var t=typeof a,key=t==="number"||t==="boolean"||!p&&t==="object"?a:t==="string"?JSON.stringify(t):p(a);if(!p&&t==="object"){var r;return wm.m.get(key)||(!c||c(key,wm.m),wm.m.set(key,r=fn.call(this,a)),r)}return s[key]||(!c||c(key,s),s[key]=fn.call(this,a))}.bind(this,fn,s,wm,maxAge>0&&maxAge<I?d:0,serializer);u=1}else{f=function(f,k,v,e,c,m,...a){var i,j,l=m||a.length;for(i=0;i<k.length&&v[i]!==undefined;i++){for(j=0;j<=l&&(k[i][j]===a[j]||e&&e(k[i][j],a[j]));j++){if(j===l)return v[i]}}!c||c(i,v);return v[i]=fn.apply(this,k[i]=a)}.bind(this,fn,k,v,equals,maxAge>0&&maxAge<I?d:0,maxArgs)}f.clear=(_=>{Object.keys(s).forEach(k=>delete s[k]);wm.m=new WeakMap;k.length=0;v.length=0});f.keys=(_=>u?null:k.slice());f.values=(_=>u?null:v.slice());f.keyValues=(_=>u?{primitives:Object.assign({},s),objects:wm.m}:null);return f};if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this)},{}]},{},[1]);
(function() {
"use strict";
const vrgs = f => {
const s = f+"",
var vrgs = f => {
var s = f+"",
i = s.indexOf("...");

@@ -11,7 +10,7 @@ return i>=0 && i<s.indexOf(")" || s.indexOf("arguments")>=0);

equals, // equality tester, will force use of slower multiarg approach even for single arg functions
maxAge, // max cache age is ms, set higher than 0 if you want automatic clearing
maxAge, // max cache age is ms, set > 0 && < Infinity if you want automatic clearing
maxArgs, // max args to use for signature
vargs = vrgs(fn) // set to true if function may have variable or beyond-signature arguments, default if best attempt at infering
}={}) => {
const s = Object.create(null), // single arg function key/value cache
var s = Object.create(null), // single arg function key/value cache
k = [], // multiple arg function arg key cache

@@ -23,5 +22,5 @@ v = [], // multiple arg function result cache

},maxAge),
I = Infinity;
let f, // memoized function to return
u; // flag indicating a unary arg function is in use
I = Infinity,
f, // memoized function to return
u; // flag indicating a unary arg function is in use for clear operation
if(fn.length===1 && !equals && !vargs) {

@@ -37,7 +36,7 @@ // for single argument functions, just use a JS object key look-up

// strings must be serialized because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const t = typeof a,
var t = typeof a,
key = t === "number" || t === "boolean" || (!p && t === "object") ? a : t === "string" ? JSON.stringify(t) : p(a);
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(!p && t==="object") {
let r;
var r;
return wm.m.get(key) || ((!c||c(key,wm.m)),wm.m.set(key,r = fn.call(this, a)),r);

@@ -51,3 +50,3 @@ }

wm,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
serializer

@@ -67,17 +66,10 @@ );

f = (function(f,k,v,e,c,m,...a) {
const l = m||a.length;
let i;
for(i=0;i<k.length;i++) { // an array of arrays of args, each array represents a call signature
let p = k[i];
if(p && p.length===a.length) {
for(let j=0;j<=l;j++) {
if(e ? !e(p[j],a[j]) : p[j]!==a[j]) break; // go to next call signature if args don't match
if(j===l) { // the args matched
if(v[i]!==undefined) return v[i];
}
}
var i,j,l = m||a.length; // use var, slightly smaller and faster for loops, and i needs more scope
for(i=0;i<k.length && v[i]!==undefined;i++) { // an array of arrays of args, each array represents a call signature
for(j=0;j<=l && (k[i][j]===a[j] || (e && e(k[i][j],a[j])));j++) { // compare each arg //if(p[j]!==a[j] && (!e || !e(p[j],a[j]))) break; // go to next call signature if args don't match
if(j===l) return v[i]; // the args matched
}
}
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(c) c(i,v);
!c||c(i,v);
return v[i] = fn.apply(this,k[i] = a);

@@ -90,3 +82,3 @@ }).bind(

equals,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
maxArgs

@@ -93,0 +85,0 @@ );

@@ -1,1 +0,1 @@

(function(){"use strict";const vrgs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)},nanomemoize=(fn,{serializer:serializer,equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=vrgs(fn)}={})=>{const s=Object.create(null),k=[],v=[],wm={m:new WeakMap},d=(key,c)=>setTimeout(()=>{c instanceof WeakMap?c.delete(key):delete c[key]},maxAge),I=Infinity;let f,u;if(fn.length===1&&!equals&&!vargs){f=function(f,s,wm,c,p,a){const t=typeof a,key=t==="number"||t==="boolean"||!p&&t==="object"?a:t==="string"?JSON.stringify(t):p(a);if(!p&&t==="object"){let r;return wm.m.get(key)||(!c||c(key,wm.m),wm.m.set(key,r=fn.call(this,a)),r)}return s[key]||(!c||c(key,s),s[key]=fn.call(this,a))}.bind(this,fn,s,wm,maxAge&&maxAge<I?d:0,serializer);u=1}else{f=function(f,k,v,e,c,m,...a){const l=m||a.length;let i;for(i=0;i<k.length;i++){let p=k[i];if(p&&p.length===a.length){for(let j=0;j<=l;j++){if(e?!e(p[j],a[j]):p[j]!==a[j])break;if(j===l){if(v[i]!==undefined)return v[i]}}}}if(c)c(i,v);return v[i]=fn.apply(this,k[i]=a)}.bind(this,fn,k,v,equals,maxAge&&maxAge<I?d:0,maxArgs)}f.clear=(_=>{Object.keys(s).forEach(k=>delete s[k]);wm.m=new WeakMap;k.length=0;v.length=0});f.keys=(_=>u?null:k.slice());f.values=(_=>u?null:v.slice());f.keyValues=(_=>u?{primitives:Object.assign({},s),objects:wm.m}:null);return f};if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this);
(function(){var vrgs=f=>{var s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)},nanomemoize=(fn,{serializer:serializer,equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=vrgs(fn)}={})=>{var s=Object.create(null),k=[],v=[],wm={m:new WeakMap},d=(key,c)=>setTimeout(()=>{c instanceof WeakMap?c.delete(key):delete c[key]},maxAge),I=Infinity,f,u;if(fn.length===1&&!equals&&!vargs){f=function(f,s,wm,c,p,a){var t=typeof a,key=t==="number"||t==="boolean"||!p&&t==="object"?a:t==="string"?JSON.stringify(t):p(a);if(!p&&t==="object"){var r;return wm.m.get(key)||(!c||c(key,wm.m),wm.m.set(key,r=fn.call(this,a)),r)}return s[key]||(!c||c(key,s),s[key]=fn.call(this,a))}.bind(this,fn,s,wm,maxAge>0&&maxAge<I?d:0,serializer);u=1}else{f=function(f,k,v,e,c,m,...a){var i,j,l=m||a.length;for(i=0;i<k.length&&v[i]!==undefined;i++){for(j=0;j<=l&&(k[i][j]===a[j]||e&&e(k[i][j],a[j]));j++){if(j===l)return v[i]}}!c||c(i,v);return v[i]=fn.apply(this,k[i]=a)}.bind(this,fn,k,v,equals,maxAge>0&&maxAge<I?d:0,maxArgs)}f.clear=(_=>{Object.keys(s).forEach(k=>delete s[k]);wm.m=new WeakMap;k.length=0;v.length=0});f.keys=(_=>u?null:k.slice());f.values=(_=>u?null:v.slice());f.keyValues=(_=>u?{primitives:Object.assign({},s),objects:wm.m}:null);return f};if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this);
(function() {
"use strict";
const vrgs = f => {
const s = f+"",
var vrgs = f => {
var s = f+"",
i = s.indexOf("...");

@@ -11,7 +10,7 @@ return i>=0 && i<s.indexOf(")" || s.indexOf("arguments")>=0);

equals, // equality tester, will force use of slower multiarg approach even for single arg functions
maxAge, // max cache age is ms, set higher than 0 if you want automatic clearing
maxAge, // max cache age is ms, set > 0 && < Infinity if you want automatic clearing
maxArgs, // max args to use for signature
vargs = vrgs(fn) // set to true if function may have variable or beyond-signature arguments, default if best attempt at infering
}={}) => {
const s = Object.create(null), // single arg function key/value cache
var s = Object.create(null), // single arg function key/value cache
k = [], // multiple arg function arg key cache

@@ -23,5 +22,5 @@ v = [], // multiple arg function result cache

},maxAge),
I = Infinity;
let f, // memoized function to return
u; // flag indicating a unary arg function is in use
I = Infinity,
f, // memoized function to return
u; // flag indicating a unary arg function is in use for clear operation
if(fn.length===1 && !equals && !vargs) {

@@ -37,7 +36,7 @@ // for single argument functions, just use a JS object key look-up

// strings must be serialized because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const t = typeof a,
var t = typeof a,
key = t === "number" || t === "boolean" || (!p && t === "object") ? a : t === "string" ? JSON.stringify(t) : p(a);
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(!p && t==="object") {
let r;
var r;
return wm.m.get(key) || ((!c||c(key,wm.m)),wm.m.set(key,r = fn.call(this, a)),r);

@@ -51,3 +50,3 @@ }

wm,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
serializer

@@ -67,17 +66,10 @@ );

f = (function(f,k,v,e,c,m,...a) {
const l = m||a.length;
let i;
for(i=0;i<k.length;i++) { // an array of arrays of args, each array represents a call signature
let p = k[i];
if(p && p.length===a.length) {
for(let j=0;j<=l;j++) {
if(e ? !e(p[j],a[j]) : p[j]!==a[j]) break; // go to next call signature if args don't match
if(j===l) { // the args matched
if(v[i]!==undefined) return v[i];
}
}
var i,j,l = m||a.length; // use var, slightly smaller and faster for loops, and i needs more scope
for(i=0;i<k.length && v[i]!==undefined;i++) { // an array of arrays of args, each array represents a call signature
for(j=0;j<=l && (k[i][j]===a[j] || (e && e(k[i][j],a[j])));j++) { // compare each arg //if(p[j]!==a[j] && (!e || !e(p[j],a[j]))) break; // go to next call signature if args don't match
if(j===l) return v[i]; // the args matched
}
}
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(c) c(i,v);
!c||c(i,v);
return v[i] = fn.apply(this,k[i] = a);

@@ -90,3 +82,3 @@ }).bind(

equals,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
maxArgs

@@ -93,0 +85,0 @@ );

{
"name": "nano-memoize",
"version": "v1.1.1",
"version": "v1.1.2",
"description": "Faster than fast, smaller than micro ... a nano speed and nano size memoizer.",

@@ -8,3 +8,3 @@ "engines": {},

"scripts": {
"prepare": "cp ./src/nano-memoize.js ./index.js && cp ./src/nano-memoize.js dist/nano-memoize.js && browserify ./src/nano-memoize.js -o browser/nano-memoize.js && uglifyjs browser/nano-memoize.js -o browser/nano-memoize.min.js && uglifyjs src/nano-memoize.js -o dist/nano-memoize.min.js"
"prepare": "cp ./src/nano-memoize.js ./index.js && cp ./src/nano-memoize.js dist/nano-memoize.js && npx bread-compressor dist && browserify ./src/nano-memoize.js -o browser/nano-memoize.js && uglifyjs browser/nano-memoize.js -o browser/nano-memoize.min.js && uglifyjs src/nano-memoize.js -o dist/nano-memoize.min.js"
},

@@ -30,2 +30,3 @@ "repository": {

"blanket": "^1.2.3",
"bread-compressor-cli": "^1.0.6",
"chai": "^3.4.1",

@@ -32,0 +33,0 @@ "cli-table2": "^0.2.0",

@@ -8,133 +8,132 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/30ce201484754fa5b0a6c6046abb842d)](https://www.codacy.com/app/syblackwell/nano-memoize?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=anywhichway/nano-memoize&amp;utm_campaign=Badge_Grade)

During development we also discovered that despite its popularity and goal to be the fastest possible memoizer, `fast-memoize` is actually one of the slowest out-of-the-box when it comes to multiple argument functions. It uses `JSON.stringify` as key generator. It also only memoizes out to 3 arguments. This is not to say it should not be used, it also seems to have the cleanest software architecture and it may be theoretically possible to write a high-speed multi-argument plugin. And, MANY people are very happy with it.
During development we also discovered that despite its popularity and goal to be the fastest possible memoizer, `fast-memoize` is actually one of the slowest out-of-the-box when it comes to multiple argument functions because it uses `JSON.stringify` to generate a single key generator for all arguments. It also only memoizes out to 3 arguments, which may cause issues. This is not to say it should not be used, it also seems to have the cleanest software architecture and it may be theoretically possible to write a high-speed multi-argument plugin. And, MANY people are very happy with it.
Special appreciation to @titoBouzout and @popbee who spent a good bit of time reviewing code for optimization and making recommendations. See [Issue 4](https://github.com/anywhichway/nano-memoize/issues/4) for the conversation.
The minified/brotli size is 640 Brotli bytes for `nano-memoize` v1.1.0 vs 2020 bytes for `micro-memoize` v3.0.1. And, `nano-memoize` has slightly more functionality.
The minified/brotli size is 665 bytes for `nano-memoize` v1.1.0 vs 1,356 bytes for `micro-memoize` v3.0.1. And, `nano-memoize` has slightly more functionality.
The speed tests are below. In most cases `nano-memoize` is the fastest.
The speed tests are below.
* For single primitive argument functions it is comparable to, but slightly and probably un-importantly faster that `fast-memoize`.
* For single primitive argument functions `nano-memoize` and `fast-memoize` will trade-off first position across multiple test runs with `nano-memoize` winning slightly more frequently. They are 4x faster than `micro-memoize`.
* For single primitive argument functions it is comparable to, but slightly and probably un-importantly faster that `fast-memoize`.
* For single object argument functions it is, 10-15% faster than `fast-memoize` and 20-25% faster than `micro-memoize`.
* For multiple primitive argument functions`nano-memoize` is slightly and probably un-importantly faster than `micro-memoize`.
* For multiple primitive argument functions `nano-memoize` and `micro-memoize` will trade-off first position across multiple test runs with `nano-memoize` winning slightly more frequently. They are 60x faster than `fast-memoize`.
* For multiple object argument functions `nano-memoize` is slightly and probably un-importantly faster than `micro-memoize`.
* For multiple object argument functions `nano-memoize` and `micro-memoize` will trade-off first position across multiple test runs with `nano-memoize` winning slightly more frequently. They are 60x faster than `fast-memoize`.
* When `deepEquals` tests are used, `micro-memoize` rules the day.
We have found that benchmarks can vary dramatically from O/S to O/S or Node version to Node version. These tests were run on a Windows 10 64bit 2.4ghz machine with 8GB RAM and Node v11.6.0. Also, even with multiple samplings, garbage collection can have a substative impact and multiple runs in different orders are really required for apples-to-apples comparisons.
We have found that benchmarks can vary dramatically from O/S to O/S or Node version to Node version. These tests were run on a Windows 10 Pro 64bit 1.8ghz i7 machine with 16GB RAM and Node v11.6.0. Also, even with multiple samplings, garbage collection can have a substative impact and multiple runs in different orders are really required for apples-to-apples comparisons.
Functions with a single primitive parameter...
```
+----------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+----------------------------------------------------------------------+
� nano-memoize � 408,626,233 � � 1.86% � 81 �
+----------------------------------------------------------------------+
� fast-memoize � 368,639,842 � � 1.79% � 81 �
+----------------------------------------------------------------------+
� micro-memoize � 102,964,021 � � 1.39% � 84 �
+----------------------------------------------------------------------+
� moize � 93,623,511 � � 1.70% � 83 �
+----------------------------------------------------------------------+
� iMemoized � 83,667,946 � � 1.58% � 83 �
+----------------------------------------------------------------------+
� lru-memoize � 71,258,447 � � 1.90% � 82 �
+----------------------------------------------------------------------+
� lodash � 46,706,263 � � 1.87% � 82 �
+----------------------------------------------------------------------+
� memoizee � 36,960,053 � � 1.67% � 81 �
+----------------------------------------------------------------------+
� underscore � 34,650,172 � � 1.67% � 79 �
+----------------------------------------------------------------------+
� memoizerific � 6,854,333 � � 2.14% � 79 �
+----------------------------------------------------------------------+
� addy-osmani � 6,076,478 � � 1.80% � 80 �
+----------------------------------------------------------------------+
```
Functions with a single object parameter...
```
+----------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+----------------------------------------------------------------------+
� nano-memoize � 120,054,209 � � 1.77% � 86 �
+----------------------------------------------------------------------+
� micro-memoize � 88,968,257 � � 1.13% � 84 �
+----------------------------------------------------------------------+
� moize � 85,218,895 � � 1.42% � 84 �
+----------------------------------------------------------------------+
� fast-memoize � 73,730,097 � � 5.40% � 71 �
+----------------------------------------------------------------------+
� iMemoized � 58,513,510 � � 1.26% � 80 �
+----------------------------------------------------------------------+
� lodash � 46,264,060 � � 1.88% � 80 �
+----------------------------------------------------------------------+
� lru-memoize � 30,648,600 � � 1.61% � 81 �
+----------------------------------------------------------------------+
� underscore � 28,901,663 � � 2.98% � 75 �
+----------------------------------------------------------------------+
� memoizee � 17,213,563 � � 1.68% � 80 �
+----------------------------------------------------------------------+
� addy-osmani � 6,379,759 � � 1.75% � 81 �
+----------------------------------------------------------------------+
� memoizerific � 5,789,710 � � 3.67% � 74 �
+----------------------------------------------------------------------+
```
Functions with multiple parameters that contain only primitives...
```
+---------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------------------------------------------------------------+
� nano-memoize � 59,229,772 � � 0.72% � 75 �
� nano-memoize � 64,477,579 � � 1.77% � 83 �
+---------------------------------------------------------------------+
� fast-memoize � 53,557,422 � � 4.65% � 61 �
� moize � 56,501,764 � � 2.20% � 79 �
+---------------------------------------------------------------------+
� micro-memoize � 11,102,228 � � 9.04% � 56 �
� micro-memoize � 39,469,612 � � 6.47% � 72 �
+---------------------------------------------------------------------+
� iMemoized � 10,207,666 � � 11.93% � 40 �
� lru-memoize � 19,361,408 � � 6.19% � 70 �
+---------------------------------------------------------------------+
� moize � 7,753,586 � � 41.02% � 57 �
� memoizee � 11,381,474 � � 4.35% � 73 �
+---------------------------------------------------------------------+
� lodash � 6,364,484 � � 11.60% � 43 �
� iMemoized � 5,733,044 � � 9.82% � 71 �
+---------------------------------------------------------------------+
� lru-memoize � 4,383,453 � � 39.83% � 59 �
� addy-osmani � 3,258,073 � � 2.34% � 86 �
+---------------------------------------------------------------------+
� underscore � 4,159,229 � � 13.33% � 64 �
� memoizerific � 1,965,125 � � 7.60% � 64 �
+---------------------------------------------------------------------+
� memoizee � 4,067,506 � � 19.14% � 40 �
� fast-memoize � 834,173 � � 7.38% � 65 �
+---------------------------------------------------------------------+
� memoizerific � 1,145,407 � � 4.27% � 65 �
+---------------------------------------------------------------------+
� addy-osmani � 639,076 � � 22.97% � 57 �
+---------------------------------------------------------------------+
```
Functions with a single object parameter...
Functions with multiple parameters that contain objects...
```
+--------------------------------------------------------------------+
+---------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+--------------------------------------------------------------------+
� nano-memoize � 20,377,511 � � 2.18% � 71 �
+--------------------------------------------------------------------+
� fast-memoize � 15,132,122 � � 6.55% � 60 �
+--------------------------------------------------------------------+
� micro-memoize � 15,128,905 � � 4.30% � 62 �
+--------------------------------------------------------------------+
� moize � 11,712,302 � � 4.93% � 61 �
+--------------------------------------------------------------------+
� iMemoized � 10,145,254 � � 3.17% � 62 �
+--------------------------------------------------------------------+
� lodash � 7,161,180 � � 3.72% � 59 �
+--------------------------------------------------------------------+
� underscore � 5,789,882 � � 2.62% � 70 �
+--------------------------------------------------------------------+
� lru-memoize � 3,881,960 � � 4.34% � 61 �
+--------------------------------------------------------------------+
� memoizee � 2,566,037 � � 1.66% � 67 �
+--------------------------------------------------------------------+
� memoizerific � 1,111,770 � � 1.80% � 78 �
+--------------------------------------------------------------------+
� addy-osmani � 1,001,119 � � 4.98% � 61 �
+--------------------------------------------------------------------+
+---------------------------------------------------------------------+
� nano-memoize � 63,382,702 � � 1.88% � 83 �
+---------------------------------------------------------------------+
� moize � 61,349,765 � � 1.78% � 82 �
+---------------------------------------------------------------------+
� micro-memoize � 54,322,737 � � 4.53% � 72 �
+---------------------------------------------------------------------+
� lru-memoize � 23,824,559 � � 2.34% � 81 �
+---------------------------------------------------------------------+
� memoizee � 11,161,431 � � 1.97% � 84 �
+---------------------------------------------------------------------+
� memoizerific � 5,416,184 � � 3.89% � 79 �
+---------------------------------------------------------------------+
� addy-osmani � 1,199,529 � � 2.78% � 84 �
+---------------------------------------------------------------------+
� fast-memoize � 1,057,876 � � 1.75% � 83 �
+---------------------------------------------------------------------+
```
Functions with multiple parameters that contain only primitives...
```
+--------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+--------------------------------------------------------------------+
� nano-memoize � 7,109,499 � � 3.64% � 67 �
+--------------------------------------------------------------------+
� micro-memoize � 7,052,676 � � 5.64% � 61 �
+--------------------------------------------------------------------+
� moize � 6,470,805 � � 2.41% � 72 �
+--------------------------------------------------------------------+
� lru-memoize � 3,128,711 � � 3.89% � 69 �
+--------------------------------------------------------------------+
� memoizee � 1,770,348 � � 16.76% � 57 �
+--------------------------------------------------------------------+
� iMemoized � 1,004,645 � � 19.13% � 58 �
+--------------------------------------------------------------------+
� memoizerific � 690,537 � � 11.49% � 57 �
+--------------------------------------------------------------------+
� addy-osmani � 421,059 � � 5.01% � 68 �
+--------------------------------------------------------------------+
� fast-memoize � 253,637 � � 2.84% � 66 �
+--------------------------------------------------------------------+
```
Functions with multiple parameters that contain objects...
```
+--------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+--------------------------------------------------------------------+
� nano-memoize � 7,115,350 � � 3.16% � 66 �
+--------------------------------------------------------------------+
� micro-memoize � 6,868,295 � � 3.63% � 66 �
+--------------------------------------------------------------------+
� moize � 4,196,397 � � 24.14% � 61 �
+--------------------------------------------------------------------+
� lru-memoize � 3,284,142 � � 2.82% � 68 �
+--------------------------------------------------------------------+
� memoizee � 1,333,993 � � 3.18% � 70 �
+--------------------------------------------------------------------+
� memoizerific � 807,252 � � 6.46% � 72 �
+--------------------------------------------------------------------+
� addy-osmani � 218,191 � � 3.84% � 73 �
+--------------------------------------------------------------------+
� fast-memoize � 175,937 � � 8.04% � 59 �
+--------------------------------------------------------------------+
```
Deep equals ...

@@ -158,9 +157,3 @@

We were puzzled about the multiple argument performance on `fast-memoize` given its stated goal of being the "fastest possible". We discovered that the default caching and serialization approach used by fast-memoize only performs well for single argument functions for two reasons:
1) It uses `JSON.stringify` to create a key for an entire argument list. This can be slow.
2) Because a single key is generated for all arguments when perhaps only the first argument differs in a call, a lot of extra work is done. The `moize` and `micro-memoize` approach adopted by `nano-memoize` is far faster for multiple arguments.
# Usage

@@ -195,5 +188,5 @@

maxAge: number,
// the serializer/key generator to use for single argument functions (multi-argument functionsuse equals)
// the serializer/key generator to use for single argument functions (optional, not recommended)
serializer: function,
// the equals function to use for multi-argument functions, e.g. deepEquals for objects (single-argument functions serializer)
// the equals function to use for multi-argument functions (optional, try to avoid) e.g. deepEquals for objects
equals: function,

@@ -209,2 +202,4 @@ // forces the use of multi-argument paradigm, auto set if function has a spread argument or uses `arguments` in its body.

2019-04-02 v1.1.2 Speed improvements for multiple arguments. Now consistently faster than `fast-memoize` and `nano-memoize` across multiple test runs. Benchmarks run in a new test environment. The benchmarks for v1.1.1 although correct from a relative perspective, grossly understated actual performance due to a corrupt testing environment.
2019-03-25 v1.1.1 Pushed incorrect version with v1.1.0. This corrects the version push.

@@ -211,0 +206,0 @@

(function() {
"use strict";
const vrgs = f => {
const s = f+"",
var vrgs = f => {
var s = f+"",
i = s.indexOf("...");

@@ -11,7 +10,7 @@ return i>=0 && i<s.indexOf(")" || s.indexOf("arguments")>=0);

equals, // equality tester, will force use of slower multiarg approach even for single arg functions
maxAge, // max cache age is ms, set higher than 0 if you want automatic clearing
maxAge, // max cache age is ms, set > 0 && < Infinity if you want automatic clearing
maxArgs, // max args to use for signature
vargs = vrgs(fn) // set to true if function may have variable or beyond-signature arguments, default if best attempt at infering
}={}) => {
const s = Object.create(null), // single arg function key/value cache
var s = Object.create(null), // single arg function key/value cache
k = [], // multiple arg function arg key cache

@@ -23,5 +22,5 @@ v = [], // multiple arg function result cache

},maxAge),
I = Infinity;
let f, // memoized function to return
u; // flag indicating a unary arg function is in use
I = Infinity,
f, // memoized function to return
u; // flag indicating a unary arg function is in use for clear operation
if(fn.length===1 && !equals && !vargs) {

@@ -37,7 +36,7 @@ // for single argument functions, just use a JS object key look-up

// strings must be serialized because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const t = typeof a,
var t = typeof a,
key = t === "number" || t === "boolean" || (!p && t === "object") ? a : t === "string" ? JSON.stringify(t) : p(a);
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(!p && t==="object") {
let r;
var r;
return wm.m.get(key) || ((!c||c(key,wm.m)),wm.m.set(key,r = fn.call(this, a)),r);

@@ -51,3 +50,3 @@ }

wm,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
serializer

@@ -67,17 +66,10 @@ );

f = (function(f,k,v,e,c,m,...a) {
const l = m||a.length;
let i;
for(i=0;i<k.length;i++) { // an array of arrays of args, each array represents a call signature
let p = k[i];
if(p && p.length===a.length) {
for(let j=0;j<=l;j++) {
if(e ? !e(p[j],a[j]) : p[j]!==a[j]) break; // go to next call signature if args don't match
if(j===l) { // the args matched
if(v[i]!==undefined) return v[i];
}
}
var i,j,l = m||a.length; // use var, slightly smaller and faster for loops, and i needs more scope
for(i=0;i<k.length && v[i]!==undefined;i++) { // an array of arrays of args, each array represents a call signature
for(j=0;j<=l && (k[i][j]===a[j] || (e && e(k[i][j],a[j])));j++) { // compare each arg //if(p[j]!==a[j] && (!e || !e(p[j],a[j]))) break; // go to next call signature if args don't match
if(j===l) return v[i]; // the args matched
}
}
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not
if(c) c(i,v);
!c||c(i,v);
return v[i] = fn.apply(this,k[i] = a);

@@ -90,3 +82,3 @@ }).bind(

equals,
maxAge && maxAge<I ? d : 0,
maxAge>0 && maxAge<I ? d : 0,
maxArgs

@@ -93,0 +85,0 @@ );

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc