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.0.0 to 1.0.1

4

benchmark/index.js

@@ -184,3 +184,3 @@ 'use strict';

})
.add('namo-memoize', () => {
.add('nano-memoize', () => {
mNano(fibonacciNumber);

@@ -259,3 +259,3 @@ })

})
.add('namo-memoize', () => {
.add('nano-memoize', () => {
mNano(fibonacciNumber);

@@ -262,0 +262,0 @@ })

(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 hasVargs = (f) => {
const hsVrgs = (f) => {
const s = f+"",

@@ -10,12 +10,12 @@ i = s.indexOf("...");

function nanomemoize (fn, options={}) {
// for single argument functions, just use a JS object key look-up
function single (f,s,change,serializer,arg) {
// for sngl argument functions, just use a JS object key look-up
function sngl (f,s,chng,serializer,arg) {
// strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const key = (!arg || typeof arg === "number" || typeof arg ==="boolean" ? arg : serializer(arg));
if(change) change(key);
if(chng) chng(key);
return s[key] || ( s[key] = f.call(this, arg));
}
// for multiple arg functions, loop through a cache of all the args
// for mltpl arg functions, loop through a cache of all the args
// looking at each arg separately so a test can abort as soon as possible
function multiple(f,k,v,eq,change,max=0,...args) {
function mltpl(f,k,v,eq,chng,max=0,...args) {
const rslt = {};

@@ -37,3 +37,3 @@ for(let i=0;i<k.length;i++) { // an array of arrays of args

const i = rslt.i>=0 ? rslt.i : v.length;
if(change) { change(i); }
if(chng) { chng(i); }
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v;

@@ -46,38 +46,33 @@ }

maxArgs,
vargs = hasVargs(fn)
vargs = hsVrgs(fn),
expireInterval = 1
} = options,
s = {}, // single arg function key/value cache
k = [], // multiple arg function arg key cache
v = [], // multiple arg function result cache
c = {}, // key change cache
change = (cache,key) => { // logs key changes
s = {}, // sngl arg function key/value cache
k = [], // mltpl arg function arg key cache
v = [], // mltpl arg function result cache
c = {}, // key chng cache
chng = (cache,key) => { // logs key chngs
c[key] = {key,cache};
},
t = {},
timeout = (change) => { // deletes timed-out keys
if(t[change.key]) { clearTimeout(t[change.key]); }
t[change.key] = setTimeout(() => {
delete change.cache[change.key];
delete t[change.key];
tmout = (chng) => { // deletes timed-out keys
if(t[chng.key]) { clearTimeout(t[chng.key]); }
t[chng.key] = setTimeout(() => {
delete chng.cache[chng.key];
delete t[chng.key];
},maxAge);
};
setInterval(() => { // process key changes out of cycle for speed
for(let p in c) {
if(maxAge) { timeout(c[p]); }
delete c[p];
}
},1);
let f,
unary = fn.length===1 && !equals && !vargs;
unry = fn.length===1 && !equals && !vargs;
// pre-bind core arguments, faster than using a closure or passing on stack or in this case using a partial
if(unary) {
f = single.bind(
if(unry) {
f = sngl.bind(
this,
fn,
s,
(maxAge ? change.bind(this,s): null), // turn change logging on and bind to arg cache s
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s
serializer
);
} else {
f = multiple.bind(
f = mltpl.bind(
this,

@@ -88,7 +83,7 @@ fn,

equals || ((a,b) => a===b), // default to just a regular strict comparison
(maxAge ? change.bind(this,v): null), // turn change logging on and bind to arg cache v
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v
maxArgs
);
}
// reset all the caches, must change array length or delete keys on objects to retain bind integrity
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity
f.clear = () => {

@@ -101,5 +96,13 @@ Object.keys(s).forEach((k) => delete s[k]);

};
f.keys = () => (!unary ? k.slice() : null);
f.values = () => (!unary ? v.slice() : null);
f.keyValues = () => (unary ? Object.assign({},s) : null);
f.keys = () => (!unry ? k.slice() : null);
f.values = () => (!unry ? v.slice() : null);
f.keyValues = () => (unry ? Object.assign({},s) : null);
if(expireInterval) {
f.interval = setInterval(() => { // process key chngs out of cycle for speed
for(const p in c) {
if(maxAge) { tmout(c[p]); }
delete c[p];
}
},expireInterval);
}
return f;

@@ -106,0 +109,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 hasVargs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)};function nanomemoize(fn,options={}){function single(f,s,change,serializer,arg){const key=!arg||typeof arg==="number"||typeof arg==="boolean"?arg:serializer(arg);if(change)change(key);return s[key]||(s[key]=f.call(this,arg))}function multiple(f,k,v,eq,change,max=0,...args){const rslt={};for(let i=0;i<k.length;i++){let key=k[i];if(max){key=key.slice(0,max)}if(key.length===args.length||max&&key.length<args.length){const max=key.length-1;for(let j=0;j<=max;j++){if(!eq(key[j],args[j])){break}if(j===max){rslt.i=i;rslt.v=v[i]}}}}const i=rslt.i>=0?rslt.i:v.length;if(change){change(i)}return typeof rslt.v==="undefined"?v[i]=f.call(this,...k[i]=args):rslt.v}const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hasVargs(fn)}=options,s={},k=[],v=[],c={},change=(cache,key)=>{c[key]={key:key,cache:cache}},t={},timeout=change=>{if(t[change.key]){clearTimeout(t[change.key])}t[change.key]=setTimeout(()=>{delete change.cache[change.key];delete t[change.key]},maxAge)};setInterval(()=>{for(let p in c){if(maxAge){timeout(c[p])}delete c[p]}},1);let f,unary=fn.length===1&&!equals&&!vargs;if(unary){f=single.bind(this,fn,s,maxAge?change.bind(this,s):null,serializer)}else{f=multiple.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?change.bind(this,v):null,maxArgs)}f.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0;Object.keys(c).forEach(k=>delete c[k]);Object.keys(t).forEach(k=>{clearTimeout(t[k]);delete t[k]})});f.keys=(()=>!unary?k.slice():null);f.values=(()=>!unary?v.slice():null);f.keyValues=(()=>unary?Object.assign({},s):null);return f}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this)},{}]},{},[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 hsVrgs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)};function nanomemoize(fn,options={}){function sngl(f,s,chng,serializer,arg){const key=!arg||typeof arg==="number"||typeof arg==="boolean"?arg:serializer(arg);if(chng)chng(key);return s[key]||(s[key]=f.call(this,arg))}function mltpl(f,k,v,eq,chng,max=0,...args){const rslt={};for(let i=0;i<k.length;i++){let key=k[i];if(max){key=key.slice(0,max)}if(key.length===args.length||max&&key.length<args.length){const max=key.length-1;for(let j=0;j<=max;j++){if(!eq(key[j],args[j])){break}if(j===max){rslt.i=i;rslt.v=v[i]}}}}const i=rslt.i>=0?rslt.i:v.length;if(chng){chng(i)}return typeof rslt.v==="undefined"?v[i]=f.call(this,...k[i]=args):rslt.v}const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hsVrgs(fn),expireInterval:expireInterval=1}=options,s={},k=[],v=[],c={},chng=(cache,key)=>{c[key]={key:key,cache:cache}},t={},tmout=chng=>{if(t[chng.key]){clearTimeout(t[chng.key])}t[chng.key]=setTimeout(()=>{delete chng.cache[chng.key];delete t[chng.key]},maxAge)};let f,unry=fn.length===1&&!equals&&!vargs;if(unry){f=sngl.bind(this,fn,s,maxAge?chng.bind(this,s):null,serializer)}else{f=mltpl.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?chng.bind(this,v):null,maxArgs)}f.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0;Object.keys(c).forEach(k=>delete c[k]);Object.keys(t).forEach(k=>{clearTimeout(t[k]);delete t[k]})});f.keys=(()=>!unry?k.slice():null);f.values=(()=>!unry?v.slice():null);f.keyValues=(()=>unry?Object.assign({},s):null);if(expireInterval){f.interval=setInterval(()=>{for(const p in c){if(maxAge){tmout(c[p])}delete c[p]}},expireInterval)}return f}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this)},{}]},{},[1]);
(function() {
"use strict";
const hasVargs = (f) => {
const hsVrgs = (f) => {
const s = f+"",

@@ -9,12 +9,12 @@ i = s.indexOf("...");

function nanomemoize (fn, options={}) {
// for single argument functions, just use a JS object key look-up
function single (f,s,change,serializer,arg) {
// for sngl argument functions, just use a JS object key look-up
function sngl (f,s,chng,serializer,arg) {
// strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const key = (!arg || typeof arg === "number" || typeof arg ==="boolean" ? arg : serializer(arg));
if(change) change(key);
if(chng) chng(key);
return s[key] || ( s[key] = f.call(this, arg));
}
// for multiple arg functions, loop through a cache of all the args
// for mltpl arg functions, loop through a cache of all the args
// looking at each arg separately so a test can abort as soon as possible
function multiple(f,k,v,eq,change,max=0,...args) {
function mltpl(f,k,v,eq,chng,max=0,...args) {
const rslt = {};

@@ -36,3 +36,3 @@ for(let i=0;i<k.length;i++) { // an array of arrays of args

const i = rslt.i>=0 ? rslt.i : v.length;
if(change) { change(i); }
if(chng) { chng(i); }
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v;

@@ -45,38 +45,33 @@ }

maxArgs,
vargs = hasVargs(fn)
vargs = hsVrgs(fn),
expireInterval = 1
} = options,
s = {}, // single arg function key/value cache
k = [], // multiple arg function arg key cache
v = [], // multiple arg function result cache
c = {}, // key change cache
change = (cache,key) => { // logs key changes
s = {}, // sngl arg function key/value cache
k = [], // mltpl arg function arg key cache
v = [], // mltpl arg function result cache
c = {}, // key chng cache
chng = (cache,key) => { // logs key chngs
c[key] = {key,cache};
},
t = {},
timeout = (change) => { // deletes timed-out keys
if(t[change.key]) { clearTimeout(t[change.key]); }
t[change.key] = setTimeout(() => {
delete change.cache[change.key];
delete t[change.key];
tmout = (chng) => { // deletes timed-out keys
if(t[chng.key]) { clearTimeout(t[chng.key]); }
t[chng.key] = setTimeout(() => {
delete chng.cache[chng.key];
delete t[chng.key];
},maxAge);
};
setInterval(() => { // process key changes out of cycle for speed
for(let p in c) {
if(maxAge) { timeout(c[p]); }
delete c[p];
}
},1);
let f,
unary = fn.length===1 && !equals && !vargs;
unry = fn.length===1 && !equals && !vargs;
// pre-bind core arguments, faster than using a closure or passing on stack or in this case using a partial
if(unary) {
f = single.bind(
if(unry) {
f = sngl.bind(
this,
fn,
s,
(maxAge ? change.bind(this,s): null), // turn change logging on and bind to arg cache s
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s
serializer
);
} else {
f = multiple.bind(
f = mltpl.bind(
this,

@@ -87,7 +82,7 @@ fn,

equals || ((a,b) => a===b), // default to just a regular strict comparison
(maxAge ? change.bind(this,v): null), // turn change logging on and bind to arg cache v
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v
maxArgs
);
}
// reset all the caches, must change array length or delete keys on objects to retain bind integrity
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity
f.clear = () => {

@@ -100,5 +95,13 @@ Object.keys(s).forEach((k) => delete s[k]);

};
f.keys = () => (!unary ? k.slice() : null);
f.values = () => (!unary ? v.slice() : null);
f.keyValues = () => (unary ? Object.assign({},s) : null);
f.keys = () => (!unry ? k.slice() : null);
f.values = () => (!unry ? v.slice() : null);
f.keyValues = () => (unry ? Object.assign({},s) : null);
if(expireInterval) {
f.interval = setInterval(() => { // process key chngs out of cycle for speed
for(const p in c) {
if(maxAge) { tmout(c[p]); }
delete c[p];
}
},expireInterval);
}
return f;

@@ -105,0 +108,0 @@ }

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

(function(){"use strict";const hasVargs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)};function nanomemoize(fn,options={}){function single(f,s,change,serializer,arg){const key=!arg||typeof arg==="number"||typeof arg==="boolean"?arg:serializer(arg);if(change)change(key);return s[key]||(s[key]=f.call(this,arg))}function multiple(f,k,v,eq,change,max=0,...args){const rslt={};for(let i=0;i<k.length;i++){let key=k[i];if(max){key=key.slice(0,max)}if(key.length===args.length||max&&key.length<args.length){const max=key.length-1;for(let j=0;j<=max;j++){if(!eq(key[j],args[j])){break}if(j===max){rslt.i=i;rslt.v=v[i]}}}}const i=rslt.i>=0?rslt.i:v.length;if(change){change(i)}return typeof rslt.v==="undefined"?v[i]=f.call(this,...k[i]=args):rslt.v}const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hasVargs(fn)}=options,s={},k=[],v=[],c={},change=(cache,key)=>{c[key]={key:key,cache:cache}},t={},timeout=change=>{if(t[change.key]){clearTimeout(t[change.key])}t[change.key]=setTimeout(()=>{delete change.cache[change.key];delete t[change.key]},maxAge)};setInterval(()=>{for(let p in c){if(maxAge){timeout(c[p])}delete c[p]}},1);let f,unary=fn.length===1&&!equals&&!vargs;if(unary){f=single.bind(this,fn,s,maxAge?change.bind(this,s):null,serializer)}else{f=multiple.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?change.bind(this,v):null,maxArgs)}f.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0;Object.keys(c).forEach(k=>delete c[k]);Object.keys(t).forEach(k=>{clearTimeout(t[k]);delete t[k]})});f.keys=(()=>!unary?k.slice():null);f.values=(()=>!unary?v.slice():null);f.keyValues=(()=>unary?Object.assign({},s):null);return f}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this);
(function(){"use strict";const hsVrgs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)};function nanomemoize(fn,options={}){function sngl(f,s,chng,serializer,arg){const key=!arg||typeof arg==="number"||typeof arg==="boolean"?arg:serializer(arg);if(chng)chng(key);return s[key]||(s[key]=f.call(this,arg))}function mltpl(f,k,v,eq,chng,max=0,...args){const rslt={};for(let i=0;i<k.length;i++){let key=k[i];if(max){key=key.slice(0,max)}if(key.length===args.length||max&&key.length<args.length){const max=key.length-1;for(let j=0;j<=max;j++){if(!eq(key[j],args[j])){break}if(j===max){rslt.i=i;rslt.v=v[i]}}}}const i=rslt.i>=0?rslt.i:v.length;if(chng){chng(i)}return typeof rslt.v==="undefined"?v[i]=f.call(this,...k[i]=args):rslt.v}const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hsVrgs(fn),expireInterval:expireInterval=1}=options,s={},k=[],v=[],c={},chng=(cache,key)=>{c[key]={key:key,cache:cache}},t={},tmout=chng=>{if(t[chng.key]){clearTimeout(t[chng.key])}t[chng.key]=setTimeout(()=>{delete chng.cache[chng.key];delete t[chng.key]},maxAge)};let f,unry=fn.length===1&&!equals&&!vargs;if(unry){f=sngl.bind(this,fn,s,maxAge?chng.bind(this,s):null,serializer)}else{f=mltpl.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?chng.bind(this,v):null,maxArgs)}f.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0;Object.keys(c).forEach(k=>delete c[k]);Object.keys(t).forEach(k=>{clearTimeout(t[k]);delete t[k]})});f.keys=(()=>!unry?k.slice():null);f.values=(()=>!unry?v.slice():null);f.keyValues=(()=>unry?Object.assign({},s):null);if(expireInterval){f.interval=setInterval(()=>{for(const p in c){if(maxAge){tmout(c[p])}delete c[p]}},expireInterval)}return f}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this);
(function() {
"use strict";
const hasVargs = (f) => {
const hsVrgs = (f) => {
const s = f+"",

@@ -9,12 +9,12 @@ i = s.indexOf("...");

function nanomemoize (fn, options={}) {
// for single argument functions, just use a JS object key look-up
function single (f,s,change,serializer,arg) {
// for sngl argument functions, just use a JS object key look-up
function sngl (f,s,chng,serializer,arg) {
// strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const key = (!arg || typeof arg === "number" || typeof arg ==="boolean" ? arg : serializer(arg));
if(change) change(key);
if(chng) chng(key);
return s[key] || ( s[key] = f.call(this, arg));
}
// for multiple arg functions, loop through a cache of all the args
// for mltpl arg functions, loop through a cache of all the args
// looking at each arg separately so a test can abort as soon as possible
function multiple(f,k,v,eq,change,max=0,...args) {
function mltpl(f,k,v,eq,chng,max=0,...args) {
const rslt = {};

@@ -36,3 +36,3 @@ for(let i=0;i<k.length;i++) { // an array of arrays of args

const i = rslt.i>=0 ? rslt.i : v.length;
if(change) { change(i); }
if(chng) { chng(i); }
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v;

@@ -45,38 +45,33 @@ }

maxArgs,
vargs = hasVargs(fn)
vargs = hsVrgs(fn),
expireInterval = 1
} = options,
s = {}, // single arg function key/value cache
k = [], // multiple arg function arg key cache
v = [], // multiple arg function result cache
c = {}, // key change cache
change = (cache,key) => { // logs key changes
s = {}, // sngl arg function key/value cache
k = [], // mltpl arg function arg key cache
v = [], // mltpl arg function result cache
c = {}, // key chng cache
chng = (cache,key) => { // logs key chngs
c[key] = {key,cache};
},
t = {},
timeout = (change) => { // deletes timed-out keys
if(t[change.key]) { clearTimeout(t[change.key]); }
t[change.key] = setTimeout(() => {
delete change.cache[change.key];
delete t[change.key];
tmout = (chng) => { // deletes timed-out keys
if(t[chng.key]) { clearTimeout(t[chng.key]); }
t[chng.key] = setTimeout(() => {
delete chng.cache[chng.key];
delete t[chng.key];
},maxAge);
};
setInterval(() => { // process key changes out of cycle for speed
for(let p in c) {
if(maxAge) { timeout(c[p]); }
delete c[p];
}
},1);
let f,
unary = fn.length===1 && !equals && !vargs;
unry = fn.length===1 && !equals && !vargs;
// pre-bind core arguments, faster than using a closure or passing on stack or in this case using a partial
if(unary) {
f = single.bind(
if(unry) {
f = sngl.bind(
this,
fn,
s,
(maxAge ? change.bind(this,s): null), // turn change logging on and bind to arg cache s
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s
serializer
);
} else {
f = multiple.bind(
f = mltpl.bind(
this,

@@ -87,7 +82,7 @@ fn,

equals || ((a,b) => a===b), // default to just a regular strict comparison
(maxAge ? change.bind(this,v): null), // turn change logging on and bind to arg cache v
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v
maxArgs
);
}
// reset all the caches, must change array length or delete keys on objects to retain bind integrity
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity
f.clear = () => {

@@ -100,5 +95,13 @@ Object.keys(s).forEach((k) => delete s[k]);

};
f.keys = () => (!unary ? k.slice() : null);
f.values = () => (!unary ? v.slice() : null);
f.keyValues = () => (unary ? Object.assign({},s) : null);
f.keys = () => (!unry ? k.slice() : null);
f.values = () => (!unry ? v.slice() : null);
f.keyValues = () => (unry ? Object.assign({},s) : null);
if(expireInterval) {
f.interval = setInterval(() => { // process key chngs out of cycle for speed
for(const p in c) {
if(maxAge) { tmout(c[p]); }
delete c[p];
}
},expireInterval);
}
return f;

@@ -105,0 +108,0 @@ }

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

@@ -5,0 +5,0 @@ "engines": {},

@@ -10,23 +10,44 @@ [![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)

The speed tests are below. `nano-memoize` is the fastest in all cases. For single argument functions is it comparable to, but slightly and probably un-importantly faster than, `fast-memoize`. For multiple argument functions it is comparable to, but slightly and probably un-importantly faster than, `micro-memoize`.
The speed tests are below. In most cases `nano-memoize` is the fastest.
* 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 always by far the fastest.
* For multiple primitive argument functions functions`nano-memoize` slightly and probably un-importantly faster than `fast-memoize`.
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 v9.4.0.
* For multiple object argument functions `fast-memoize` slightly and probably un-importantly faster.
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 v9.4.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 | 152,526,010 | � 2.58% | 80 |
| fast-memoize | 147,683,192 | � 2.90% | 85 |
| micro-memoize | 22,682,348 | � 3.69% | 75 |
| iMemoized | 22,292,411 | � 4.47% | 72 |
| lodash | 20,937,311 | � 1.94% | 88 |
| moize | 16,296,876 | � 4.77% | 74 |
| memoizee | 9,651,118 | � 3.07% | 86 |
| underscore | 9,266,277 | � 2.66% | 75 |
| lru-memoize | 6,676,849 | � 2.93% | 87 |
| addy-osmani | 3,899,834 | � 2.27% | 86 |
| memoizerific | 3,753,347 | � 2.33% | 86 |
| ramda | 493,665 | � 1.77% | 88 |
+----------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------+-------------+--------------------------+-------------�
� namo-memoize � 277,174,954 � � 0.39% � 94 �
+---------------+-------------+--------------------------+-------------�
� fast-memoize � 243,829,313 � � 4.97% � 81 �
+---------------+-------------+--------------------------+-------------�
� iMemoized � 49,406,719 � � 3.90% � 82 �
+---------------+-------------+--------------------------+-------------�
� micro-memoize � 48,245,239 � � 2.19% � 89 �
+---------------+-------------+--------------------------+-------------�
� moize � 47,380,879 � � 0.59% � 88 �
+---------------+-------------+--------------------------+-------------�
� lru-memoize � 39,284,232 � � 4.35% � 87 �
+---------------+-------------+--------------------------+-------------�
� lodash � 31,464,058 � � 2.91% � 91 �
+---------------+-------------+--------------------------+-------------�
� memoizee � 19,406,111 � � 4.90% � 79 �
+---------------+-------------+--------------------------+-------------�
� underscore � 16,986,840 � � 5.83% � 75 �
+---------------+-------------+--------------------------+-------------�
� addy-osmani � 4,496,619 � � 0.98% � 92 �
+---------------+-------------+--------------------------+-------------�
� memoizerific � 2,394,952 � � 6.96% � 49 �
+---------------+-------------+--------------------------+-------------�
� ramda � 1,095,063 � � 2.10% � 86 �
+----------------------------------------------------------------------+

@@ -36,16 +57,21 @@

| Name | Ops / sec | Relative margin of error | Sample size |
|---------------|------------|--------------------------|-------------|
| nano-memoize | 53,741,011 | � 2.06% | 85 |
| fast-memoize | 51,041,370 | � 2.40% | 82 |
| micro-memoize | 22,638,078 | � 3.96% | 77 |
| lodash | 22,187,376 | � 1.72% | 83 |
| moize | 19,446,817 | � 3.32% | 81 |
| underscore | 13,643,959 | � 3.17% | 81 |
| iMemoized | 11,926,976 | � 5.90% | 80 |
| memoizee | 8,010,016 | � 1.99% | 83 |
| lru-memoize | 5,709,156 | � 1.89% | 89 |
| memoizerific | 3,817,781 | � 1.46% | 90 |
| addy-osmani | 3,699,956 | � 3.30% | 85 |
| ramda | 793,756 | � 1.92% | 87 |
+----------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------+-------------+--------------------------+-------------�
� namo-memoize � 271,647,146 � 0.74% � 90 �
+---------------+-------------+--------------------------+-------------�
� micro-memoize � 44,126,430 � 4.22% � 81 �
+---------------+-------------+--------------------------+-------------�
� fast-memoize � 44,125,722 � 2.14% � 82 �
+---------------+-------------+--------------------------+-------------�
� iMemoized � 43,981,304 � 1.61% � 89 �
+---------------+-------------+--------------------------+-------------�
� moize � 32,603,505 � 3.19% � 14 �
+---------------+-------------+--------------------------+-------------�
� lodash � 31,277,037 � 1.16% � 88 �
+---------------+-------------+--------------------------+-------------�
� underscore � 20,293,644 � 1.02% � 88 �
+---------------+-------------+--------------------------+-------------�
� memoizee � 11,533,134 � 1.35% � 89 �
+---------------+-------------+--------------------------+-------------�

@@ -55,13 +81,23 @@

| Name | Ops / sec | Relative margin of error | Sample size |
|---------------|------------|--------------------------|-------------|
| nano-memoize | 18,408,074 | � 1.24% | 85 |
| micro-memoize | 17,310,593 | � 1.11% | 85 |
| moize | 14,457,697 | � 0.79% | 90 |
| memoizee | 7,723,320 | � 0.54% | 94 |
| iMemoized | 5,934,041 | � 1.03% | 90 |
| lru-memoize | 5,388,273 | � 0.52% | 94 |
| memoizerific | 3,206,479 | � 0.30% | 93 |
| addy-osmani | 2,397,744 | � 0.48% | 93 |
| fast-memoize | 899,483 | � 0.37% | 91 |
+---------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------+------------+--------------------------+-------------�
� nano-memoize � 24,739,433 � 0.98% � 85 �
+---------------+------------+--------------------------+-------------�
� micro-memoize � 23,131,341 � 3.33% � 74 �
+---------------+------------+--------------------------+-------------�
� moize � 20,241,359 � 2.45% � 81 �
+---------------+------------+--------------------------+-------------�
� memoizee � 9,917,821 � 2.58% � 85 �
+---------------+------------+--------------------------+-------------�
� lru-memoize � 7,582,999 � 2.85% � 82 �
+---------------+------------+--------------------------+-------------�
� iMemoized � 4,765,891 � 12.92% � 68 �
+---------------+------------+--------------------------+-------------�
� memoizerific � 3,200,253 � 3.02% � 84 �
+---------------+------------+--------------------------+-------------�
� addy-osmani � 2,240,692 � 2.28% � 87 �
+---------------+------------+--------------------------+-------------�
� fast-memoize � 885,271 � 3.99% � 82 �
+---------------------------------------------------------------------+

@@ -71,12 +107,21 @@

| Name | Ops / sec | Relative margin of error | Sample size |
|---------------|------------|--------------------------|-------------|
| nano-memoize | 13,869,690 | � 1.25% | 86 |
| micro-memoize | 13,192,239 | � 3.13% | 78 |
| moize | 10,895,627 | � 3.33% | 71 |
| memoizee | 5,794,981 | � 0.83% | 92 |
| lru-memoize | 5,148,065 | � 0.44% | 92 |
| memoizerific | 3,206,713 | � 0.86% | 93 |
| addy-osmani | 996,705 | � 0.45% | 92 |
| fast-memoize | 699,597 | � 1.17% | 91 |
+---------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------+------------+--------------------------+-------------�
� micro-memoize � 23,846,343 � 3.35% � 84 �
+---------------+------------+--------------------------+-------------�
� nano-memoize � 17,861,879 � 2.49% � 84 �
+---------------+------------+--------------------------+-------------�
� moize � 17,147,054 � 5.62% � 63 �
+---------------+------------+--------------------------+-------------�
� lru-memoize � 7,247,819 � 3.85% � 81 �
+---------------+------------+--------------------------+-------------�
� memoizee � 6,860,227 � 1.17% � 88 �
+---------------+------------+--------------------------+-------------�
� memoizerific � 3,399,423 � 2.60% � 85 �
+---------------+------------+--------------------------+-------------�
� addy-osmani � 795,071 � 1.43% � 85 �
+---------------+------------+--------------------------+-------------�
� fast-memoize � 715,841 � 1.05% � 86 �
+---------------------------------------------------------------------+

@@ -87,9 +132,15 @@

| Name | Ops / sec | Relative margin of error | Sample size |
|---------------------------------------------------|------------|--------------------------|-------------|
| nano-memoize deep equals (lodash isEqual) | 18,024,422 | � 1.78% | 83 |
| micro-memoize deep equals (lodash isEqual) | 17,219,476 | � 0.69% | 86 |
| nano-memoize deep equals (fast-equals deepEqual) | 14,732,731 | � 3.10% | 85 |
| micro-memoize deep equals (fast-equals deepEqual) | 8,785,408 | � 11.28% | 51 |
| micro-memoize deep equals (hash-it isEqual) | 5,744,080 | � 10.69% | 48 |
+---------------------------------------------------------------------------------------------------------+
� Name � Ops / sec � Relative margin of error � Sample size �
+---------------------------------------------------+------------+--------------------------+-------------�
� micro-memoize deep equals (lodash isEqual) � 37,582,028 � 1.87% � 83 �
+---------------------------------------------------+------------+--------------------------+-------------�
� micro-memoize deep equals (fast-equals deepEqual) � 21,181,692 � 6.75% � 66 �
+---------------------------------------------------+------------+--------------------------+-------------�
� nanomemoize deep equals (fast-equals deepEqual) � 17,186,548 � 3.22% � 80 �
+---------------------------------------------------+------------+--------------------------+-------------�
� nanomemoize deep equals (lodash isEqual) � 14,995,992 � 3.49% � 75 �
+---------------------------------------------------+------------+--------------------------+-------------�
� micro-memoize deep equals (hash-it isEqual) � 14,376,860 � 3.27% � 78 �
+---------------------------------------------------------------------------------------------------------+

@@ -106,5 +157,5 @@

npm install nano-memoize
`npm install nano-memoize`
use the code in the `browser` directory for the browser
Use the code in the [`browser`](browser/) directory for the browser

@@ -130,11 +181,21 @@ Since most devs are running a build pipeline, the code is not transpiled, although it is browserified

{
maxArgs: number, // only use the provided maxArgs for cache look-up, useful for ignoring final callback arguments
maxAge: number, // number of milliseconds to cache a result
serializer: function, // the serializer/key generator to use for single argument functions (multi-argument functions do not use a serializer)
equals: function, // the equals function to use for multi-argument functions, e.g. deepEquals for objects (single-argument functions use serializer not equals)
vargs: boolean // forces the use of multi-argument paradigm, auto set if function has a spread argument or uses `arguments` in its body.
// only use the provided maxArgs for cache look-up, useful for ignoring final callback arguments
maxArgs: number,
// number of milliseconds to cache a result
maxAge: number,
// the serializer/key generator to use for single argument functions (multi-argument functionsuse equals)
serializer: function,
// the equals function to use for multi-argument functions, e.g. deepEquals for objects (single-argument functions serializer)
equals: function,
// forces the use of multi-argument paradigm, auto set if function has a spread argument or uses `arguments` in its body.
vargs: boolean
// number of milliseconds between checks to expire memos, defaults to 1, set to 0 if you want to disable
expireInterval: number,
}
```
# Release History (reverse chronological order)
2019-02-16 v1.0.1 Memo expiration optimization. Issue 4 addressed.
2018-04-13 v1.0.0 Code style improvements.

@@ -160,2 +221,2 @@

2018=01-24 v0.0.1a ALPHA First public release. Benchmark code in repository not yet running.
2018=01-24 v0.0.1a ALPHA First public release. Benchmark code in repository not yet running.
(function() {
"use strict";
const hasVargs = (f) => {
const hsVrgs = (f) => {
const s = f+"",

@@ -9,12 +9,12 @@ i = s.indexOf("...");

function nanomemoize (fn, options={}) {
// for single argument functions, just use a JS object key look-up
function single (f,s,change,serializer,arg) {
// for sngl argument functions, just use a JS object key look-up
function sngl (f,s,chng,serializer,arg) {
// strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1"
const key = (!arg || typeof arg === "number" || typeof arg ==="boolean" ? arg : serializer(arg));
if(change) change(key);
if(chng) chng(key);
return s[key] || ( s[key] = f.call(this, arg));
}
// for multiple arg functions, loop through a cache of all the args
// for mltpl arg functions, loop through a cache of all the args
// looking at each arg separately so a test can abort as soon as possible
function multiple(f,k,v,eq,change,max=0,...args) {
function mltpl(f,k,v,eq,chng,max=0,...args) {
const rslt = {};

@@ -36,3 +36,3 @@ for(let i=0;i<k.length;i++) { // an array of arrays of args

const i = rslt.i>=0 ? rslt.i : v.length;
if(change) { change(i); }
if(chng) { chng(i); }
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v;

@@ -45,38 +45,33 @@ }

maxArgs,
vargs = hasVargs(fn)
vargs = hsVrgs(fn),
expireInterval = 1
} = options,
s = {}, // single arg function key/value cache
k = [], // multiple arg function arg key cache
v = [], // multiple arg function result cache
c = {}, // key change cache
change = (cache,key) => { // logs key changes
s = {}, // sngl arg function key/value cache
k = [], // mltpl arg function arg key cache
v = [], // mltpl arg function result cache
c = {}, // key chng cache
chng = (cache,key) => { // logs key chngs
c[key] = {key,cache};
},
t = {},
timeout = (change) => { // deletes timed-out keys
if(t[change.key]) { clearTimeout(t[change.key]); }
t[change.key] = setTimeout(() => {
delete change.cache[change.key];
delete t[change.key];
tmout = (chng) => { // deletes timed-out keys
if(t[chng.key]) { clearTimeout(t[chng.key]); }
t[chng.key] = setTimeout(() => {
delete chng.cache[chng.key];
delete t[chng.key];
},maxAge);
};
setInterval(() => { // process key changes out of cycle for speed
for(let p in c) {
if(maxAge) { timeout(c[p]); }
delete c[p];
}
},1);
let f,
unary = fn.length===1 && !equals && !vargs;
unry = fn.length===1 && !equals && !vargs;
// pre-bind core arguments, faster than using a closure or passing on stack or in this case using a partial
if(unary) {
f = single.bind(
if(unry) {
f = sngl.bind(
this,
fn,
s,
(maxAge ? change.bind(this,s): null), // turn change logging on and bind to arg cache s
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s
serializer
);
} else {
f = multiple.bind(
f = mltpl.bind(
this,

@@ -87,7 +82,7 @@ fn,

equals || ((a,b) => a===b), // default to just a regular strict comparison
(maxAge ? change.bind(this,v): null), // turn change logging on and bind to arg cache v
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v
maxArgs
);
}
// reset all the caches, must change array length or delete keys on objects to retain bind integrity
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity
f.clear = () => {

@@ -100,5 +95,13 @@ Object.keys(s).forEach((k) => delete s[k]);

};
f.keys = () => (!unary ? k.slice() : null);
f.values = () => (!unary ? v.slice() : null);
f.keyValues = () => (unary ? Object.assign({},s) : null);
f.keys = () => (!unry ? k.slice() : null);
f.values = () => (!unry ? v.slice() : null);
f.keyValues = () => (unry ? Object.assign({},s) : null);
if(expireInterval) {
f.interval = setInterval(() => { // process key chngs out of cycle for speed
for(const p in c) {
if(maxAge) { tmout(c[p]); }
delete c[p];
}
},expireInterval);
}
return f;

@@ -105,0 +108,0 @@ }

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