nano-memoize
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -10,3 +10,13 @@ (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 nanomemoize (fn, options={}) { | ||
// for sngl argument functions, just use a JS object key look-up | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn) | ||
} = options, | ||
s = {}, // single arg function key/value cache | ||
k = [], // multiple arg function arg key cache | ||
v = []; // multiple arg function result cache | ||
// for single argument functions, just use a JS object key look-up | ||
function sngl (f,s,chng,serializer,arg) { | ||
@@ -16,5 +26,5 @@ // strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1" | ||
if(chng) chng(key); | ||
return s[key] || ( s[key] = f.call(this, arg)); | ||
return s[key] || (s[key] = f.call(this, arg)); | ||
} | ||
// for mltpl arg functions, loop through a cache of all the args | ||
// for multiple arg functions, loop through a cache of all the args | ||
// looking at each arg separately so a test can abort as soon as possible | ||
@@ -38,41 +48,18 @@ function mltpl(f,k,v,eq,chng,max=0,...args) { | ||
const i = rslt.i>=0 ? rslt.i : v.length; | ||
if(chng) { chng(i); } | ||
if(chng) chng(i); | ||
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v; | ||
} | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn), | ||
expireInterval = 1 | ||
} = options, | ||
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 = {}, | ||
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); | ||
}; | ||
let f, | ||
let m, | ||
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(unry) { | ||
f = sngl.bind( | ||
m = sngl.bind( | ||
this, | ||
fn, | ||
s, | ||
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s | ||
maxAge ? (key) => setTimeout(() => { delete s[key]; },maxAge) : null, | ||
serializer | ||
); | ||
} else { | ||
f = mltpl.bind( | ||
m = mltpl.bind( | ||
this, | ||
@@ -83,3 +70,3 @@ fn, | ||
equals || ((a,b) => a===b), // default to just a regular strict comparison | ||
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v | ||
maxAge ? (key) => setTimeout(() => { delete v[key]; },maxAge) : null, | ||
maxArgs | ||
@@ -89,23 +76,12 @@ ); | ||
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity | ||
f.clear = () => { | ||
m.clear = () => { | ||
Object.keys(s).forEach((k) => delete s[k]); | ||
k.length = 0; //k.splice(0,k.length); | ||
v.length = 0; //v.splice(0,v.length); | ||
Object.keys(c).forEach(k => delete c[k]); | ||
Object.keys(t).forEach(k => { clearTimeout(t[k]); delete t[k]; }); | ||
k.length = 0; | ||
v.length = 0; | ||
}; | ||
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; | ||
m.keys = () => (!unry ? k.slice() : null); | ||
m.values = () => (!unry ? v.slice() : null); | ||
m.keyValues = () => (unry ? Object.assign({},s) : null); | ||
return m; | ||
} | ||
if(typeof(module)!=="undefined") module.exports = nanomemoize; | ||
@@ -112,0 +88,0 @@ if(typeof(window)!=="undefined") window.nanomemoize = nanomemoize; |
@@ -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 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 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={}){const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hsVrgs(fn)}=options,s={},k=[],v=[];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}let m,unry=fn.length===1&&!equals&&!vargs;if(unry){m=sngl.bind(this,fn,s,maxAge?key=>setTimeout(()=>{delete s[key]},maxAge):null,serializer)}else{m=mltpl.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?key=>setTimeout(()=>{delete v[key]},maxAge):null,maxArgs)}m.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0});m.keys=(()=>!unry?k.slice():null);m.values=(()=>!unry?v.slice():null);m.keyValues=(()=>unry?Object.assign({},s):null);return m}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this)},{}]},{},[1]); |
@@ -9,3 +9,13 @@ (function() { | ||
function nanomemoize (fn, options={}) { | ||
// for sngl argument functions, just use a JS object key look-up | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn) | ||
} = options, | ||
s = {}, // single arg function key/value cache | ||
k = [], // multiple arg function arg key cache | ||
v = []; // multiple arg function result cache | ||
// for single argument functions, just use a JS object key look-up | ||
function sngl (f,s,chng,serializer,arg) { | ||
@@ -15,5 +25,5 @@ // strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1" | ||
if(chng) chng(key); | ||
return s[key] || ( s[key] = f.call(this, arg)); | ||
return s[key] || (s[key] = f.call(this, arg)); | ||
} | ||
// for mltpl arg functions, loop through a cache of all the args | ||
// for multiple arg functions, loop through a cache of all the args | ||
// looking at each arg separately so a test can abort as soon as possible | ||
@@ -37,41 +47,18 @@ function mltpl(f,k,v,eq,chng,max=0,...args) { | ||
const i = rslt.i>=0 ? rslt.i : v.length; | ||
if(chng) { chng(i); } | ||
if(chng) chng(i); | ||
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v; | ||
} | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn), | ||
expireInterval = 1 | ||
} = options, | ||
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 = {}, | ||
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); | ||
}; | ||
let f, | ||
let m, | ||
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(unry) { | ||
f = sngl.bind( | ||
m = sngl.bind( | ||
this, | ||
fn, | ||
s, | ||
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s | ||
maxAge ? (key) => setTimeout(() => { delete s[key]; },maxAge) : null, | ||
serializer | ||
); | ||
} else { | ||
f = mltpl.bind( | ||
m = mltpl.bind( | ||
this, | ||
@@ -82,3 +69,3 @@ fn, | ||
equals || ((a,b) => a===b), // default to just a regular strict comparison | ||
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v | ||
maxAge ? (key) => setTimeout(() => { delete v[key]; },maxAge) : null, | ||
maxArgs | ||
@@ -88,23 +75,12 @@ ); | ||
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity | ||
f.clear = () => { | ||
m.clear = () => { | ||
Object.keys(s).forEach((k) => delete s[k]); | ||
k.length = 0; //k.splice(0,k.length); | ||
v.length = 0; //v.splice(0,v.length); | ||
Object.keys(c).forEach(k => delete c[k]); | ||
Object.keys(t).forEach(k => { clearTimeout(t[k]); delete t[k]; }); | ||
k.length = 0; | ||
v.length = 0; | ||
}; | ||
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; | ||
m.keys = () => (!unry ? k.slice() : null); | ||
m.values = () => (!unry ? v.slice() : null); | ||
m.keyValues = () => (unry ? Object.assign({},s) : null); | ||
return m; | ||
} | ||
if(typeof(module)!=="undefined") module.exports = nanomemoize; | ||
@@ -111,0 +87,0 @@ if(typeof(window)!=="undefined") window.nanomemoize = nanomemoize; |
@@ -1,1 +0,1 @@ | ||
(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 hsVrgs=f=>{const s=f+"",i=s.indexOf("...");return i>=0&&i<s.indexOf(")"||s.indexOf("arguments")>=0)};function nanomemoize(fn,options={}){const{serializer:serializer=(value=>JSON.stringify(value)),equals:equals,maxAge:maxAge,maxArgs:maxArgs,vargs:vargs=hsVrgs(fn)}=options,s={},k=[],v=[];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}let m,unry=fn.length===1&&!equals&&!vargs;if(unry){m=sngl.bind(this,fn,s,maxAge?key=>setTimeout(()=>{delete s[key]},maxAge):null,serializer)}else{m=mltpl.bind(this,fn,k,v,equals||((a,b)=>a===b),maxAge?key=>setTimeout(()=>{delete v[key]},maxAge):null,maxArgs)}m.clear=(()=>{Object.keys(s).forEach(k=>delete s[k]);k.length=0;v.length=0});m.keys=(()=>!unry?k.slice():null);m.values=(()=>!unry?v.slice():null);m.keyValues=(()=>unry?Object.assign({},s):null);return m}if(typeof module!=="undefined")module.exports=nanomemoize;if(typeof window!=="undefined")window.nanomemoize=nanomemoize}).call(this); |
76
index.js
@@ -9,3 +9,13 @@ (function() { | ||
function nanomemoize (fn, options={}) { | ||
// for sngl argument functions, just use a JS object key look-up | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn) | ||
} = options, | ||
s = {}, // single arg function key/value cache | ||
k = [], // multiple arg function arg key cache | ||
v = []; // multiple arg function result cache | ||
// for single argument functions, just use a JS object key look-up | ||
function sngl (f,s,chng,serializer,arg) { | ||
@@ -15,5 +25,5 @@ // strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1" | ||
if(chng) chng(key); | ||
return s[key] || ( s[key] = f.call(this, arg)); | ||
return s[key] || (s[key] = f.call(this, arg)); | ||
} | ||
// for mltpl arg functions, loop through a cache of all the args | ||
// for multiple arg functions, loop through a cache of all the args | ||
// looking at each arg separately so a test can abort as soon as possible | ||
@@ -37,41 +47,18 @@ function mltpl(f,k,v,eq,chng,max=0,...args) { | ||
const i = rslt.i>=0 ? rslt.i : v.length; | ||
if(chng) { chng(i); } | ||
if(chng) chng(i); | ||
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v; | ||
} | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn), | ||
expireInterval = 1 | ||
} = options, | ||
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 = {}, | ||
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); | ||
}; | ||
let f, | ||
let m, | ||
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(unry) { | ||
f = sngl.bind( | ||
m = sngl.bind( | ||
this, | ||
fn, | ||
s, | ||
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s | ||
maxAge ? (key) => setTimeout(() => { delete s[key]; },maxAge) : null, | ||
serializer | ||
); | ||
} else { | ||
f = mltpl.bind( | ||
m = mltpl.bind( | ||
this, | ||
@@ -82,3 +69,3 @@ fn, | ||
equals || ((a,b) => a===b), // default to just a regular strict comparison | ||
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v | ||
maxAge ? (key) => setTimeout(() => { delete v[key]; },maxAge) : null, | ||
maxArgs | ||
@@ -88,23 +75,12 @@ ); | ||
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity | ||
f.clear = () => { | ||
m.clear = () => { | ||
Object.keys(s).forEach((k) => delete s[k]); | ||
k.length = 0; //k.splice(0,k.length); | ||
v.length = 0; //v.splice(0,v.length); | ||
Object.keys(c).forEach(k => delete c[k]); | ||
Object.keys(t).forEach(k => { clearTimeout(t[k]); delete t[k]; }); | ||
k.length = 0; | ||
v.length = 0; | ||
}; | ||
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; | ||
m.keys = () => (!unry ? k.slice() : null); | ||
m.values = () => (!unry ? v.slice() : null); | ||
m.keyValues = () => (unry ? Object.assign({},s) : null); | ||
return m; | ||
} | ||
if(typeof(module)!=="undefined") module.exports = nanomemoize; | ||
@@ -111,0 +87,0 @@ if(typeof(window)!=="undefined") window.nanomemoize = nanomemoize; |
{ | ||
"name": "nano-memoize", | ||
"version": "v1.0.1", | ||
"version": "v1.0.2", | ||
"description": "Faster than fast, smaller than micro ... a nano speed and nano size memoizer.", | ||
@@ -5,0 +5,0 @@ "engines": {}, |
@@ -8,3 +8,3 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/30ce201484754fa5b0a6c6046abb842d)](https://www.codacy.com/app/syblackwell/nano-memoize?utm_source=github.com&utm_medium=referral&utm_content=anywhichway/nano-memoize&utm_campaign=Badge_Grade) | ||
The minified/gzipped size is 887 bytes for `nano-memoize` vs 959 bytes for `micro-memoize`. And, `nano-memoize` has slightly more functionality. | ||
The minified/gzipped size is 589 bytes for `nano-memoize` vs 959 bytes for `micro-memoize`. And, `nano-memoize` has slightly more functionality. | ||
@@ -29,3 +29,3 @@ The speed tests are below. In most cases `nano-memoize` is the fastest. | ||
+---------------+-------------+--------------------------+-------------� | ||
� namo-memoize � 277,174,954 � � 0.39% � 94 � | ||
� nano-memoize � 277,174,954 � � 0.39% � 94 � | ||
+---------------+-------------+--------------------------+-------------� | ||
@@ -61,3 +61,3 @@ � fast-memoize � 243,829,313 � � 4.97% � 81 � | ||
+---------------+-------------+--------------------------+-------------� | ||
� namo-memoize � 271,647,146 � 0.74% � 90 � | ||
� nano-memoize � 271,647,146 � 0.74% � 90 � | ||
+---------------+-------------+--------------------------+-------------� | ||
@@ -188,4 +188,2 @@ � micro-memoize � 44,126,430 � 4.22% � 81 � | ||
vargs: boolean | ||
// number of milliseconds between checks to expire memos, defaults to 1, set to 0 if you want to disable | ||
expireInterval: number, | ||
} | ||
@@ -196,2 +194,4 @@ ``` | ||
2019-02-16 v1.0.2 Further optimizations to deal with Issue 4. `expireInterval` introduced in v1.0.1 removed since it is no longer needed. Also, 25% reduction in size. Code no longer thrashes when memoizing a large number of functions. | ||
2019-02-16 v1.0.1 Memo expiration optimization. Issue 4 addressed. | ||
@@ -198,0 +198,0 @@ |
@@ -9,3 +9,13 @@ (function() { | ||
function nanomemoize (fn, options={}) { | ||
// for sngl argument functions, just use a JS object key look-up | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn) | ||
} = options, | ||
s = {}, // single arg function key/value cache | ||
k = [], // multiple arg function arg key cache | ||
v = []; // multiple arg function result cache | ||
// for single argument functions, just use a JS object key look-up | ||
function sngl (f,s,chng,serializer,arg) { | ||
@@ -15,5 +25,5 @@ // strings must be stringified because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1" | ||
if(chng) chng(key); | ||
return s[key] || ( s[key] = f.call(this, arg)); | ||
return s[key] || (s[key] = f.call(this, arg)); | ||
} | ||
// for mltpl arg functions, loop through a cache of all the args | ||
// for multiple arg functions, loop through a cache of all the args | ||
// looking at each arg separately so a test can abort as soon as possible | ||
@@ -37,41 +47,18 @@ function mltpl(f,k,v,eq,chng,max=0,...args) { | ||
const i = rslt.i>=0 ? rslt.i : v.length; | ||
if(chng) { chng(i); } | ||
if(chng) chng(i); | ||
return typeof rslt.v === "undefined" ? v[i] = f.call(this,...(k[i] = args)) : rslt.v; | ||
} | ||
const { | ||
serializer = (value) => JSON.stringify(value), | ||
equals, | ||
maxAge, | ||
maxArgs, | ||
vargs = hsVrgs(fn), | ||
expireInterval = 1 | ||
} = options, | ||
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 = {}, | ||
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); | ||
}; | ||
let f, | ||
let m, | ||
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(unry) { | ||
f = sngl.bind( | ||
m = sngl.bind( | ||
this, | ||
fn, | ||
s, | ||
(maxAge ? chng.bind(this,s): null), // turn chng logging on and bind to arg cache s | ||
maxAge ? (key) => setTimeout(() => { delete s[key]; },maxAge) : null, | ||
serializer | ||
); | ||
} else { | ||
f = mltpl.bind( | ||
m = mltpl.bind( | ||
this, | ||
@@ -82,3 +69,3 @@ fn, | ||
equals || ((a,b) => a===b), // default to just a regular strict comparison | ||
(maxAge ? chng.bind(this,v): null), // turn chng logging on and bind to arg cache v | ||
maxAge ? (key) => setTimeout(() => { delete v[key]; },maxAge) : null, | ||
maxArgs | ||
@@ -88,23 +75,12 @@ ); | ||
// reset all the caches, must chng array length or delete keys on objects to retain bind integrity | ||
f.clear = () => { | ||
m.clear = () => { | ||
Object.keys(s).forEach((k) => delete s[k]); | ||
k.length = 0; //k.splice(0,k.length); | ||
v.length = 0; //v.splice(0,v.length); | ||
Object.keys(c).forEach(k => delete c[k]); | ||
Object.keys(t).forEach(k => { clearTimeout(t[k]); delete t[k]; }); | ||
k.length = 0; | ||
v.length = 0; | ||
}; | ||
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; | ||
m.keys = () => (!unry ? k.slice() : null); | ||
m.values = () => (!unry ? v.slice() : null); | ||
m.keyValues = () => (unry ? Object.assign({},s) : null); | ||
return m; | ||
} | ||
if(typeof(module)!=="undefined") module.exports = nanomemoize; | ||
@@ -111,0 +87,0 @@ if(typeof(window)!=="undefined") window.nanomemoize = nanomemoize; |
@@ -61,3 +61,3 @@ var chai, | ||
}); | ||
it("expires content",function(done) { | ||
it("expires content single",function(done) { | ||
const expiring = nanomemoize((a) => a,{maxAge:5}); | ||
@@ -71,2 +71,14 @@ expect(expiring(1)).to.equal(1); | ||
}); | ||
it("expires content multiple",function(done) { | ||
const expiring = nanomemoize((a,b) => { return {a,b}; },{maxAge:5}), | ||
result = expiring(1,2); | ||
expect(result.a).to.equal(1); | ||
expect(result.b).to.equal(2); | ||
expect(expiring.values()[0].a).to.equal(1); | ||
expect(expiring.values()[0].b).to.equal(2); | ||
setTimeout(() => { | ||
expect(expiring.values()[0]).to.equal(undefined); | ||
done(); | ||
},20) | ||
}); | ||
it("clear cache",function() { | ||
@@ -73,0 +85,0 @@ const value = 1; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
49564
853