nano-memoize
Advanced tools
Comparing version 2.0.0 to 3.0.0
@@ -27,2 +27,8 @@ 'use strict'; | ||
const vm = require("node:vm"); | ||
const v8 = require("v8"); | ||
v8.setFlagsFromString('--expose_gc'); | ||
const gc = vm.runInNewContext('gc'); | ||
const Benchmark = require('benchmark'); | ||
@@ -40,6 +46,6 @@ const Table = require('cli-table2'); | ||
const lruMemoize = require('lru-memoize').default; | ||
const moize = require('moize').default; | ||
const microMemoize = require('micro-memoize'); | ||
const iMemoized = require('iMemoized'); | ||
const nanomemoize = require('../src/nano-memoize.js'); | ||
const nanomemoize = require('../index.js'); | ||
const moize = require('moize'); | ||
@@ -83,2 +89,3 @@ | ||
ora(event.target.name).succeed(); | ||
gc(); | ||
}; | ||
@@ -111,2 +118,23 @@ | ||
const fibonacciSingleArray = (array) => { | ||
return array[0] < 2 | ||
? array[0] | ||
: fibonacciSingleArray([array[0] - 1]) + | ||
fibonacciSingleArray([array[0] - 2]); | ||
}; | ||
const fibonacciMultipleArray = (array, check) => { | ||
if (check[0]) { | ||
return array[0]; | ||
} | ||
const firstValue = array[0] - 1; | ||
const secondValue = array[0] - 2; | ||
return ( | ||
fibonacciMultipleArray([firstValue], [firstValue < 2]) + | ||
fibonacciMultipleArray([secondValue], [secondValue < 2]) | ||
); | ||
}; | ||
const fibonacciMultipleObject = (number, check) => { | ||
@@ -113,0 +141,0 @@ if (check.isComplete) { |
57
index.js
@@ -42,3 +42,3 @@ (function() { | ||
z, // index of zero arg result in v | ||
wm = new WeakMap(), | ||
cache = new Map(), | ||
d = function(key,c,k) { return setTimeout(function() { | ||
@@ -50,3 +50,3 @@ if(k) { // dealing with multi-arg function, c and k are Arrays | ||
} // dealing with single arg function, c is a WekMap or Object | ||
c instanceof WeakMap ? c.delete(key) : delete c[key]; | ||
c instanceof Map ? c.delete(key) : delete c[key]; | ||
},o.maxAge); }, | ||
@@ -60,14 +60,8 @@ c = o.maxAge>0 && o.maxAge<Infinity ? d : 0, // cache change timeout, | ||
if(fn.length===1 && !o.equals && !vargs) { | ||
// for single argument functions, just use a JS object key look-up | ||
f = (function(a) { | ||
// strings must be serialized because cache[1] should not equal or overwrite cache["1"] for value = 1 and value = "1" | ||
var t = typeof a; | ||
// set chng timeout only when new value computed, hits will not push out the tte, but it is arguable they should not | ||
if(!srlz && ((t==="object" && a) || t==="function")) { | ||
// for single argument functions, just use a Map lookup | ||
f = function(a) { | ||
if(srlz) a = srlz(a); | ||
var r; | ||
return wm.get(a) || ((!c||c(a,wm)),wm.set(a,r = fn.call(this, a)),r); | ||
} | ||
var key = t === "number" || t === "boolean" || a == null ? a : t === "string" ? JSON.stringify(a) : srlz(a); | ||
return s[key] || ((!c||c(key,s)),s[key] = fn.call(this, a)); | ||
}).bind(this); | ||
return cache.get(a) || ((!c||c(a,cache)),cache.set(a,r = fn.call(this, a)),r); | ||
}; | ||
u = 1; | ||
@@ -77,22 +71,22 @@ } else { | ||
// looking at each arg separately so a test can abort as soon as possible | ||
f = (function() { | ||
var al = arguments.length; | ||
if (!al && z != null) return v[z]; | ||
var l = maxargs||al, | ||
i; | ||
for(i=k.length-1;i>=0;i--) { // an array of arrays of args, each array represents a call signature | ||
if (!maxargs && k[i].length !== l) continue; // cache miss if called with a different number of args | ||
for(var j=l-1;j>=0 && eq(k[i][j],arguments[j]);j--) { // compare each arg | ||
if(j===0) { return v[i]; } // the args matched | ||
f = function() { | ||
if(arguments.length || o.equals) { | ||
var l = maxargs||arguments.length, kl = k.length, i=kl; | ||
while(--i>=0) { // an array of arrays of args, each array represents a call signature | ||
if (!maxargs && k[i].length !== l) continue; // cache miss if called with a different number of args | ||
var j=l-1; | ||
while(j-->=0 && (o.equals ? o.equals(k[i][j],arguments[j]) : k[i][j]===arguments[i])) { // compare each arg working back from length or args || maxargs | ||
if(j===0) { return v[i]; } // the args matched | ||
} | ||
} | ||
} | ||
i = k.length - (i + 1); | ||
if (!al && z == null) z = i; | ||
// set change timeout only when new value computed, hits will not push out the tte, but it is arguable they should not | ||
return (!c||c(i,v,k)),v[i] = fn.apply(this,k[i] = arguments); | ||
}).bind(this); | ||
i = kl - (i + 1); | ||
// set change timeout only when new value computed, hits will not push out the tte, but it is arguable they should not | ||
return (!c||c(i,v,k)),v[i] = fn.apply(this,k[i] = arguments); | ||
} // set change timeout only when new value computed, hits will not push out the tte, but it is arguable they should not | ||
return z===undefined ? ((!c||c(0,v,k)),z = fn.apply(this,arguments)) : z; | ||
}; | ||
} | ||
// reset all the caches | ||
f.clear = function() { | ||
wm = new WeakMap(); | ||
cache = new Map(); | ||
s = Object.create(null); | ||
@@ -103,5 +97,4 @@ k = []; | ||
}; | ||
f.keys = function() { return u ? null : k.slice(); }; | ||
f.values = function() { return u ? null : v.slice(); }; | ||
f.keyValues = function() { return u ? {primitives:assign({},s),objects:wm} : null; }; | ||
f.keys = function() { return u ? [...cache.keys()] : k.slice(); }; | ||
f.values = function() { return u ? [...cache.values()] : v.slice(); }; | ||
return f; | ||
@@ -108,0 +101,0 @@ } |
{ | ||
"name": "nano-memoize", | ||
"version": "v2.0.0", | ||
"version": "v3.0.0", | ||
"description": "Faster than fast, smaller than micro ... a nano speed and nano size memoizer.", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"type:": "module", | ||
"source": "src/index.js", | ||
"main": "dist/nano-memoize.js", | ||
"module": "../index.js", | ||
"engines": {}, | ||
@@ -11,3 +13,6 @@ "sideEffects": false, | ||
"scripts": { | ||
"test": "mocha ./test/index.js" | ||
"test": "mocha ./test/index.js", | ||
"prepublish": "npm run build", | ||
"watch": "parcel watch", | ||
"build": "parcel build" | ||
}, | ||
@@ -51,9 +56,9 @@ "repository": { | ||
"mocha": "^10.0.0", | ||
"moize": "^5.4.4", | ||
"moize": "^6.1.5", | ||
"ora": "^1.4.0", | ||
"parcel": "^2.8.3", | ||
"ramda": "^0.26.1", | ||
"uglify-es": "^3.3.9", | ||
"underscore": "^1.9.1" | ||
}, | ||
"dependencies": {} | ||
} | ||
} | ||
} |
266
README.md
@@ -6,164 +6,119 @@ [![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 devs [caiogondim](https://github.com/caiogondim) and [planttheidea](https://github.com/planttheidea) have produced great memoizers. | ||
We analyzed their code to see if we could build something faster than [fast-memoize](https://github.com/caiogondim/fastmemoize.js) and | ||
smaller than [micro-memoize](https://github.com/planttheidea/micromemoize) while adding back some of the functionality of | ||
[moize](https://github.com/planttheidea/moize) removed in micro-memoize. We think we have done it ... but credit to them ... we just | ||
merged the best ideas in both and eliminated excess code. | ||
Version 3.x.x of nano-memoize was modified to use newer versions of JavaScript built-in classes and take advantage of current v8 loop optimizations. As a result, the minified/brotli size at 733 bytes is slightly smaller and it is generally more than 25% faster that v2.x.x and v1.x.x. | ||
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. | ||
Our tests show it is the nano-memoize fastest openly available JavaScript memoizer for single and multiple argument functions accepting primitives and objects. However, I have found that benchmarks can vary dramatically from O/S to O/S or Node version to Node version, so I could be wrong. These tests were run on a Windows 10 Pro 64bit 2.8ghz i7 machine with 16GB RAM and Node v18.13.0. Garbage collection was forced between each sample run to minimize its impact on results. | ||
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 789 bytes for `nano-memoize` v1.2.0 vs 1,356 bytes for `micro-memoize` v4.08. And, `nano-memoize` has | ||
slightly more functionality. | ||
The speed tests are below. At the time of testing the most recent version of `fast-memoize` 2.5.1 was a year old. The most recent | ||
version of `micro-memoize` 4.0.8 was 3 months old. | ||
The speed tests are below. | ||
* For single primitive argument functions `nano-memoize` is typically 20% faster than `fast-memoize` and is almost 2x faster than `micro-memoize`. | ||
* For single primitive argument functions `nano-memoize` is typically 1% faster than `fast-memoize` and `micro-emoize` faster. However, all three are within the margin of error of the other. | ||
* For single object argument functions `nano-memoize` is typically 30% faster than `fast-memoize` and 2x faster than `micro-memoize`. | ||
* For single object argument functions `nano-memoize` is typically 15% faster than its closest competitor `fast-memoize`. | ||
* For multiple primitive argument functions `nano-memoize` is typically 10% faster than `micro-memoize`. They are 40x faster than `fast-memoize`. | ||
* For multiple primitive argument functions `nano-memoize` is typically 56% faster than its closest competitor `moize`. | ||
* For multiple object argument functions `nano-memoize` is typically 10% faster than `micro-memoize`. They are 40x faster than `fast-memoize`. | ||
* For multiple object argument functions `nano-memoize` is typically 5% faster than faster than its closest competitor `moize`. | ||
* When `deepEquals` tests are used, `nano-memoize` is typically 5-10% faster than micro-memoize. | ||
* When `deepEquals` tests are used, `nano-memoize` is typically 5-10% faster than micro-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 | ||
Pro 64bit 1.8ghz i7 machine with 16GB RAM and Node v12.7.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. | ||
The planetheidea/moize library (which claims to be the fastest) does not include nano-memoize for comparison and the repository is not accepting comments or a pull request for some technical reason. The repository has been forked and its own benchmarking has been updated and run to confirm the results below. | ||
Functions with a single primitive parameter... | ||
``` | ||
+----------------------------------------------------------------------+ | ||
� Name � Ops / sec � Relative margin of error � Sample size � | ||
+----------------------------------------------------------------------+ | ||
� nano-memoize � 111,079,216 � � 2.37% � 78 � | ||
+----------------------------------------------------------------------+ | ||
� fast-memoize � 65,479,705 � � 3.34% � 75 � | ||
+----------------------------------------------------------------------+ | ||
� iMemoized � 62,291,787 � � 2.52% � 77 � | ||
+----------------------------------------------------------------------+ | ||
� lru-memoize � 60,937,690 � � 2.60% � 82 � | ||
+----------------------------------------------------------------------+ | ||
� micro-memoize � 55,728,952 � � 2.81% � 77 � | ||
+----------------------------------------------------------------------+ | ||
� moize � 53,819,146 � � 2.37% � 78 � | ||
+----------------------------------------------------------------------+ | ||
� lodash � 33,465,668 � � 1.62% � 83 � | ||
+----------------------------------------------------------------------+ | ||
� underscore � 29,056,353 � � 1.88% � 79 � | ||
+----------------------------------------------------------------------+ | ||
� memoizee � 26,065,006 � � 1.84% � 82 � | ||
+----------------------------------------------------------------------+ | ||
� addy-osmani � 13,832,042 � � 1.60% � 85 � | ||
+----------------------------------------------------------------------+ | ||
� memoizerific � 8,427,361 � � 1.91% � 82 � | ||
+----------------------------------------------------------------------+ | ||
``` | ||
Starting cycles for functions with a single primitive parameter... | ||
┌───────────────┬─────────────┬──────────────────────────┬─────────────┐ | ||
│ Name │ Ops / sec │ Relative margin of error │ Sample size │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ nano-memoize │ 150,014,960 │ ± 1.26% │ 88 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ fast-memoize │ 148,920,057 │ ± 1.37% │ 88 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ micro-memoize │ 148,405,982 │ ± 1.46% │ 90 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ iMemoized │ 117,844,380 │ ± 1.65% │ 88 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ moize │ 96,796,008 │ ± 1.80% │ 85 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ underscore │ 54,815,804 │ ± 1.28% │ 87 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ lodash │ 54,617,110 │ ± 1.30% │ 87 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ lru-memoize │ 41,426,130 │ ± 1.16% │ 87 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizee │ 31,747,590 │ ± 1.52% │ 85 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ addy-osmani │ 14,848,551 │ ± 1.76% │ 82 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizerific │ 12,835,863 │ ± 1.84% │ 85 │ | ||
└───────────────┴─────────────┴──────────────────────────┴─────────────┘ | ||
Functions with a single object parameter... | ||
Starting cycles for functions with a single object parameter... | ||
┌───────────────┬─────────────┬──────────────────────────┬─────────────┐ | ||
│ Name │ Ops / sec │ Relative margin of error │ Sample size │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ nano-memoize │ 144,165,784 │ ± 1.97% │ 84 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ fast-memoize │ 122,718,470 │ ± 1.63% │ 86 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ iMemoized │ 100,930,919 │ ± 1.49% │ 85 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ moize │ 95,450,776 │ ± 1.85% │ 84 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ micro-memoize │ 93,751,013 │ ± 1.66% │ 85 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ lodash │ 38,568,294 │ ± 2.87% │ 83 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ lru-memoize │ 37,967,319 │ ± 1.63% │ 81 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ underscore │ 34,559,912 │ ± 1.78% │ 86 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizee │ 26,782,013 │ ± 1.30% │ 87 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ addy-osmani │ 13,079,424 │ ± 3.60% │ 75 │ | ||
├───────────────┼─────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizerific │ 12,580,254 │ ± 1.39% │ 87 │ | ||
└───────────────┴─────────────┴──────────────────────────┴─────────────┘ | ||
``` | ||
+---------------------------------------------------------------------+ | ||
� Name � Ops / sec � Relative margin of error � Sample size � | ||
+---------------------------------------------------------------------+ | ||
� nano-memoize � 46,495,146 � � 1.97% � 80 � | ||
+---------------------------------------------------------------------+ | ||
� micro-memoize � 43,077,944 � � 2.09% � 81 � | ||
+---------------------------------------------------------------------+ | ||
� moize � 42,777,883 � � 2.78% � 77 � | ||
+---------------------------------------------------------------------+ | ||
� lru-memoize � 37,611,410 � � 1.79% � 82 � | ||
+---------------------------------------------------------------------+ | ||
� memoizee � 17,154,216 � � 2.01% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� iMemoized � 10,634,931 � � 1.49% � 87 � | ||
+---------------------------------------------------------------------+ | ||
� memoizerific � 6,097,165 � � 1.87% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� addy-osmani � 5,582,986 � � 2.31% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� fast-memoize � 1,218,211 � � 1.75% � 84 � | ||
+----------------------------------------------------------------------+ | ||
``` | ||
Starting cycles for functions with multiple parameters that contain only primitives... | ||
┌───────────────┬────────────┬──────────────────────────┬─────────────┐ | ||
│ Name │ Ops / sec │ Relative margin of error │ Sample size │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ nano-memoize │ 86,993,027 │ ± 1.48% │ 88 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ moize │ 49,205,886 │ ± 1.69% │ 83 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ micro-memoize │ 45,253,759 │ ± 4.09% │ 79 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ lru-memoize │ 29,224,659 │ ± 1.82% │ 85 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizee │ 17,142,573 │ ± 1.78% │ 81 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ iMemoized │ 11,665,279 │ ± 3.13% │ 87 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizerific │ 7,001,983 │ ± 3.62% │ 83 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ addy-osmani │ 4,129,598 │ ± 1.46% │ 87 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ fast-memoize │ 997,323 │ ± 3.34% │ 79 │ | ||
└───────────────┴────────────┴──────────────────────────┴─────────────┘ | ||
Functions with multiple parameters that contain only primitives... | ||
Starting cycles for functions with multiple parameters that contain objects... | ||
┌───────────────┬────────────┬──────────────────────────┬─────────────┐ | ||
│ Name │ Ops / sec │ Relative margin of error │ Sample size │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ nano-memoize │ 52,799,044 │ ± 4.24% │ 76 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ moize │ 49,973,673 │ ± 2.35% │ 84 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ micro-memoize │ 44,294,224 │ ± 3.18% │ 75 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ lru-memoize │ 29,373,487 │ ± 3.30% │ 82 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizee │ 16,355,420 │ ± 3.16% │ 83 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ memoizerific │ 7,556,503 │ ± 4.16% │ 79 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ addy-osmani │ 938,180 │ ± 19.16% │ 65 │ | ||
├───────────────┼────────────┼──────────────────────────┼─────────────┤ | ||
│ fast-memoize │ 671,400 │ ± 3.54% │ 81 │ | ||
└───────────────┴────────────┴──────────────────────────┴─────────────┘ | ||
``` | ||
+---------------------------------------------------------------------+ | ||
� Name � Ops / sec � Relative margin of error � Sample size � | ||
+---------------------------------------------------------------------+ | ||
� nano-memoize � 46,495,146 � � 1.97% � 80 � | ||
+---------------------------------------------------------------------+ | ||
� micro-memoize � 43,077,944 � � 2.09% � 81 � | ||
+---------------------------------------------------------------------+ | ||
� moize � 42,777,883 � � 2.78% � 77 � | ||
+---------------------------------------------------------------------+ | ||
� lru-memoize � 37,611,410 � � 1.79% � 82 � | ||
+---------------------------------------------------------------------+ | ||
� memoizee � 17,154,216 � � 2.01% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� iMemoized � 10,634,931 � � 1.49% � 87 � | ||
+---------------------------------------------------------------------+ | ||
� memoizerific � 6,097,165 � � 1.87% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� addy-osmani � 5,582,986 � � 2.31% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� fast-memoize � 1,218,211 � � 1.75% � 84 � | ||
+---------------------------------------------------------------------+ | ||
``` | ||
Functions with multiple parameters that contain objects... | ||
``` | ||
+---------------------------------------------------------------------+ | ||
� Name � Ops / sec � Relative margin of error � Sample size � | ||
+---------------------------------------------------------------------+ | ||
� nano-memoize � 48,155,435 � � 2.54% � 78 � | ||
+---------------------------------------------------------------------+ | ||
� moize � 40,315,112 � � 2.07% � 78 � | ||
+---------------------------------------------------------------------+ | ||
� micro-memoize � 39,886,911 � � 2.40% � 80 � | ||
+---------------------------------------------------------------------+ | ||
� lru-memoize � 36,058,456 � � 2.57% � 79 � | ||
+---------------------------------------------------------------------+ | ||
� memoizee � 15,785,666 � � 3.43% � 81 � | ||
+---------------------------------------------------------------------+ | ||
� memoizerific � 6,107,157 � � 2.99% � 81 � | ||
+---------------------------------------------------------------------+ | ||
� addy-osmani � 1,712,749 � � 3.02% � 83 � | ||
+---------------------------------------------------------------------+ | ||
� fast-memoize � 775,548 � � 3.24% � 80 � | ||
+---------------------------------------------------------------------+ | ||
``` | ||
Deep equals ... | ||
``` | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� Name � Ops / sec � Relative margin of error � Sample size � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� nanomemoize deep equals (lodash isEqual) � 61,286,418 � � 2.01% � 80 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� nanomemoize deep equals (hash-it isEqual) � 61,085,147 � � 4.10% � 77 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� micro-memoize deep equals (lodash isEqual) � 57,944,413 � � 3.21% � 79 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� micro-memoize deep equals (hash-it isEqual) � 54,368,987 � � 2.66% � 81 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� nanomemoize deep equals (fast-equals deepEqual) � 50,030,425 � � 3.39% � 76 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
� micro-memoize deep equals (fast-equals deepEqual) � 41,445,170 � � 2.84% � 76 � | ||
+---------------------------------------------------------------------------------------------------------+ | ||
``` | ||
# Usage | ||
@@ -201,3 +156,3 @@ | ||
// the serializer/key generator to use for single argument functions (optional, not recommended) | ||
// must be able to serialize objects and functions, by default a WeakMap is used internally without serializing | ||
// must be able to serialize objects and functions, by default a Map is used internally without serializing | ||
serializer: function, | ||
@@ -211,6 +166,15 @@ // the equals function to use for multi-argument functions (optional, try to avoid) e.g. deepEquals for objects | ||
To clear the cache you can call `.clear()` on the function returned my `nanomemoize`. | ||
The returned function will also have these methods: | ||
`.clear()` clears the cache for the function. | ||
`.keys()` returns an array of arrays with each array being the arguments provided on a call of the function. | ||
`.values()` returns an array of arrays with each array being the results of a function call with the same index position as the keys. | ||
# Release History (reverse chronological order) | ||
2022-01-28 v3.0.0 Slight size optimization. 25% speed improvement. Moved to module format. There is a known issue with providing `fast-equals` or `lodash.isEqual` as an optional comparison function. Unit tests pass, but the functions fail under load. The `hash-it` object equivalence function does work. A formerly undocumented method `.keyValues()` has been deprecated since it is no longer relevant with the new optimizations. | ||
2022-12-08 v2.0.0 Removed callTimeout from TypeScript typings since it was not implemented and there are no plans to implement. Bumped version to 2.0.0 since this may break some users. | ||
@@ -272,3 +236,3 @@ | ||
2019-02-16 v1.0.1 Memo expiration optimization. Issue 4 addressed. | ||
2019-02-16 v1.0.1 Memo expiration optimization. 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. | ||
@@ -275,0 +239,0 @@ 2018-04-13 v1.0.0 Code style improvements. |
var chai, | ||
expect, | ||
nanomemoize; | ||
nanomemoize, | ||
lodash; | ||
if(typeof(window)==="undefined") { | ||
chai = require("chai"); | ||
expect = chai.expect; | ||
nanomemoize = require("../src/nano-memoize.js"); | ||
lodash = require("lodash"); | ||
nanomemoize = require("../dist/nano-memoize.js").default; | ||
} | ||
const deepEquals = require('lodash').isEqual; | ||
function singleArg(arg) { | ||
@@ -39,15 +43,27 @@ return arg; | ||
}); | ||
it("single primitive number arg cached",function() { | ||
const value = 1, | ||
result = singleArg(value), | ||
keyvalues = singleArg.keyValues().primitives; | ||
keys = singleArg.keys(), | ||
values = singleArg.values(); | ||
expect(result).to.equal(value); | ||
expect(keyvalues[value]).to.equal(value); | ||
expect(keys[0]).to.equal(value); | ||
expect(values[0]).to.equal(result); | ||
}); | ||
it("clear cache",function() { | ||
const value = 1; | ||
singleArg.clear(); | ||
expect(singleArg.values()[0]).to.equal(undefined); | ||
expect(singleArg(value)).to.equal(value); | ||
expect(singleArg.values()[0]).to.equal(value); | ||
}); | ||
it("single primitive string arg cached",function() { | ||
singleArg.clear(); | ||
const value = "1", | ||
result = singleArg(value), | ||
keyvalues = singleArg.keyValues().primitives; | ||
expect(result).to.equal(value); | ||
expect(keyvalues[JSON.stringify(value)]).to.equal(value); | ||
keys = singleArg.keys(), | ||
values = singleArg.values(); | ||
expect(keys[0]).to.equal(value); | ||
expect(values[0]).to.equal(value); | ||
}); | ||
@@ -124,3 +140,2 @@ it("single object arg cached",function() { | ||
const arg1 = 1, arg2 = 2; | ||
expect(varArg.keyValues()).to.equal(null); | ||
expect(Array.isArray(varArg.values())).to.equal(true); | ||
@@ -132,5 +147,5 @@ expect(Array.isArray(varArg(arg1,arg2))).to.equal(true); | ||
expect(expiring(1)).to.equal(1); | ||
expect(expiring.keyValues().primitives[1]).to.equal(1); | ||
expect(expiring.values()[0]).to.equal(1); | ||
setTimeout(function() { | ||
expect(expiring.keyValues().primitives[1]).to.equal(undefined); | ||
expect(expiring.values()[0]).to.equal(undefined); | ||
done(); | ||
@@ -143,5 +158,5 @@ },20) | ||
expect(expiring(o)).to.equal(o); | ||
expect(expiring.keyValues().objects.get(o)).to.equal(o); | ||
expect(expiring.values()[0]).to.equal(o); | ||
setTimeout(function() { | ||
expect(expiring.keyValues().objects.get(o)).to.equal(undefined); | ||
expect(expiring.values()[0]).to.equal(undefined); | ||
done(); | ||
@@ -162,10 +177,11 @@ },20) | ||
}); | ||
it("clear cache",function() { | ||
const value = 1; | ||
expect(singleArg(value)).to.equal(value); | ||
expect(singleArg.keyValues().primitives[value]).to.equal(value); | ||
singleArg.clear(); | ||
expect(singleArg.keyValues().primitives[value]).to.equal(undefined); | ||
expect(singleArg(value)).to.equal(value); | ||
}); | ||
it("optional equal",function() { | ||
const optionalEqual = nanomemoize(function(a,b) { return [a,b]; },{equal:deepEquals}), | ||
[a1,a2] = optionalEqual({a:1}, {a:1}), | ||
values = optionalEqual.values(); | ||
expect(deepEquals(a1,a2)).to.equal(true); | ||
expect(values[0].length).to.equal(2); | ||
expect(deepEquals(values[0][0],a1)).to.equal(true); | ||
expect(deepEquals(values[0][1],a2)).to.equal(true); | ||
}) | ||
}); |
Sorry, the diff of this file is not supported yet
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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 5 instances 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
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
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
2282742
26
993
26
256
1
6