UNPKG

29 kBMarkdownView Raw
1[![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)
2# Faster than fast, smaller than micro ... nano-memoizer.
3
4# Introduction
5
6Version 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 728 bytes is slightly smaller and it is slightly faster that v2.x.x and v1.x.x.
7
8Our 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.
9
10The speed tests are below.
11
12* For single primitive argument functions `nano-memoize` is typically 2% faster than `fast-memoize` and `micro-emoize`. However, all three are within the margin of error of the other.
13
14* For single object argument functions `nano-memoize` is typically 15% faster than its closest competitor `fast-memoize`.
15
16* For multiple primitive argument functions `nano-memoize`, `moize` and `micro-memoize` are always the three fastest and within each others margin of error.
17
18* For multiple object argument functions `nano-memoize`, `moize` and `micro-memoize` are always the three fastest and within each others margin of error.
19
20* For custom equality functions 'nano-memoize` and `micro-memoize vary in speed depending on the equality function used. See the table below.
21
22The planetheidea/moize library (which claims to be the fastest on average) 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.
23
24
25Starting cycles for functions with a single primitive parameter...
26┌───────────────┬─────────────┬──────────────────────────┬─────────────┐
27│ Name │ Ops / sec │ Relative margin of error │ Sample size │
28├───────────────┼─────────────┼──────────────────────────┼─────────────┤
29│ nano-memoize │ 150,014,960 │ ± 1.26% │ 88 │
30├───────────────┼─────────────┼──────────────────────────┼─────────────┤
31│ fast-memoize │ 148,920,057 │ ± 1.37% │ 88 │
32├───────────────┼─────────────┼──────────────────────────┼─────────────┤
33│ micro-memoize │ 148,405,982 │ ± 1.46% │ 90 │
34├───────────────┼─────────────┼──────────────────────────┼─────────────┤
35│ iMemoized │ 117,844,380 │ ± 1.65% │ 88 │
36├───────────────┼─────────────┼──────────────────────────┼─────────────┤
37│ moize │ 96,796,008 │ ± 1.80% │ 85 │
38├───────────────┼─────────────┼──────────────────────────┼─────────────┤
39│ underscore │ 54,815,804 │ ± 1.28% │ 87 │
40├───────────────┼─────────────┼──────────────────────────┼─────────────┤
41│ lodash │ 54,617,110 │ ± 1.30% │ 87 │
42├───────────────┼─────────────┼──────────────────────────┼─────────────┤
43│ lru-memoize │ 41,426,130 │ ± 1.16% │ 87 │
44├───────────────┼─────────────┼──────────────────────────┼─────────────┤
45│ memoizee │ 31,747,590 │ ± 1.52% │ 85 │
46├───────────────┼─────────────┼──────────────────────────┼─────────────┤
47│ addy-osmani │ 14,848,551 │ ± 1.76% │ 82 │
48├───────────────┼─────────────┼──────────────────────────┼─────────────┤
49│ memoizerific │ 12,835,863 │ ± 1.84% │ 85 │
50└───────────────┴─────────────┴──────────────────────────┴─────────────┘
51
52Starting cycles for functions with a single object parameter...
53┌───────────────┬─────────────┬──────────────────────────┬─────────────┐
54│ Name │ Ops / sec │ Relative margin of error │ Sample size │
55├───────────────┼─────────────┼──────────────────────────┼─────────────┤
56│ nano-memoize │ 149,402,848 │ ± 1.20% │ 90 │
57├───────────────┼─────────────┼──────────────────────────┼─────────────┤
58│ fast-memoize │ 121,117,510 │ ± 2.41% │ 86 │
59├───────────────┼─────────────┼──────────────────────────┼─────────────┤
60│ iMemoized │ 98,480,257 │ ± 3.36% │ 85 │
61├───────────────┼─────────────┼──────────────────────────┼─────────────┤
62│ micro-memoize │ 97,781,728 │ ± 1.36% │ 87 │
63├───────────────┼─────────────┼──────────────────────────┼─────────────┤
64│ moize │ 94,370,945 │ ± 4.58% │ 84 │
65├───────────────┼─────────────┼──────────────────────────┼─────────────┤
66│ lodash │ 41,298,824 │ ± 2.60% │ 84 │
67├───────────────┼─────────────┼──────────────────────────┼─────────────┤
68│ lru-memoize │ 39,315,541 │ ± 1.55% │ 86 │
69├───────────────┼─────────────┼──────────────────────────┼─────────────┤
70│ underscore │ 33,803,044 │ ± 1.66% │ 87 │
71├───────────────┼─────────────┼──────────────────────────┼─────────────┤
72│ memoizee │ 27,298,946 │ ± 2.40% │ 86 │
73├───────────────┼─────────────┼──────────────────────────┼─────────────┤
74│ addy-osmani │ 16,003,489 │ ± 1.72% │ 87 │
75├───────────────┼─────────────┼──────────────────────────┼─────────────┤
76│ memoizerific │ 12,502,443 │ ± 1.33% │ 86 │
77└───────────────┴─────────────┴──────────────────────────┴─────────────┘
78
79Starting cycles for functions with multiple parameters that contain only primitives...
80┌───────────────┬────────────┬──────────────────────────┬─────────────┐
81│ Name │ Ops / sec │ Relative margin of error │ Sample size │
82├───────────────┼────────────┼──────────────────────────┼─────────────┤
83│ nano-memoize │ 52,311,452 │ ± 2.17% │ 84 │
84├───────────────┼────────────┼──────────────────────────┼─────────────┤
85│ moize │ 31,101,105 │ ± 19.97% │ 54 │
86├───────────────┼────────────┼──────────────────────────┼─────────────┤
87│ micro-memoize │ 28,405,348 │ ± 17.84% │ 50 │
88├───────────────┼────────────┼──────────────────────────┼─────────────┤
89│ lru-memoize │ 28,399,841 │ ± 2.86% │ 82 │
90├───────────────┼────────────┼──────────────────────────┼─────────────┤
91│ memoizee │ 16,189,445 │ ± 3.63% │ 81 │
92├───────────────┼────────────┼──────────────────────────┼─────────────┤
93│ iMemoized │ 11,294,320 │ ± 3.18% │ 80 │
94├───────────────┼────────────┼──────────────────────────┼─────────────┤
95│ memoizerific │ 6,676,755 │ ± 3.79% │ 76 │
96├───────────────┼────────────┼──────────────────────────┼─────────────┤
97│ addy-osmani │ 3,986,098 │ ± 3.61% │ 85 │
98├───────────────┼────────────┼──────────────────────────┼─────────────┤
99│ fast-memoize │ 953,862 │ ± 4.24% │ 77 │
100└───────────────┴────────────┴──────────────────────────┴─────────────┘
101
102
103Starting cycles for functions with multiple parameters that contain objects...
104┌───────────────┬────────────┬──────────────────────────┬─────────────┐
105│ Name │ Ops / sec │ Relative margin of error │ Sample size │
106├───────────────┼────────────┼──────────────────────────┼─────────────┤
107│ micro-memoize │ 52,314,935 │ ± 2.58% │ 86 │
108├───────────────┼────────────┼──────────────────────────┼─────────────┤
109│ moize │ 51,275,262 │ ± 2.11% │ 82 │
110├───────────────┼────────────┼──────────────────────────┼─────────────┤
111│ nano-memoize │ 49,070,846 │ ± 1.45% │ 86 │
112├───────────────┼────────────┼──────────────────────────┼─────────────┤
113│ lru-memoize │ 27,581,699 │ ± 4.63% │ 77 │
114├───────────────┼────────────┼──────────────────────────┼─────────────┤
115│ memoizee │ 15,915,550 │ ± 4.57% │ 79 │
116├───────────────┼────────────┼──────────────────────────┼─────────────┤
117│ memoizerific │ 7,701,634 │ ± 4.69% │ 76 │
118├───────────────┼────────────┼──────────────────────────┼─────────────┤
119│ addy-osmani │ 1,251,647 │ ± 1.81% │ 84 │
120├───────────────┼────────────┼──────────────────────────┼─────────────┤
121│ fast-memoize │ 728,772 │ ± 3.53% │ 83 │
122└───────────────┴────────────┴──────────────────────────┴─────────────┘
123
124Starting cycles for alternative cache types...
125┌─────────────────────────────────────────────────────┬─────────────┬──────────────────────────┬─────────────┐
126│ Name │ Ops / sec │ Relative margin of error │ Sample size │
127├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
128│ nanomemoize deep equals (hash-it isEqual) │ 112,560,448 │ ± 1.35% │ 85 │
129├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
130│ micro-memoize deep equals (lodash isEqual) │ 83,402,392 │ ± 2.88% │ 80 │
131├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
132│ micro-memoize deep equals (hash-it isEqual) │ 70,493,317 │ ± 2.46% │ 83 │
133├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
134│ nanomemoize deep equals (lodash isEqual) │ 63,040,211 │ ± 1.61% │ 84 │
135├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
136│ nanomemoize fast equals (fast-equals deepEqual/ES6) │ 61,878,364 │ ± 1.73% │ 84 │
137├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
138│ micro-memoize deep equals (fast-equals deepEqual) │ 56,841,180 │ ± 3.10% │ 80 │
139├─────────────────────────────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤
140│ nanomemoize fast deep equals (fast-deep-equal/ES6) │ 41,010,681 │ ± 2.44% │ 82 │
141└─────────────────────────────────────────────────────┴─────────────┴──────────────────────────┴─────────────┘
142
143
144# Usage
145
146`npm install nano-memoize`
147
148The code is hand-crafted to run across all browsers all the way back to IE 11. No transpiling is necessary.
149
150
151# API
152
153The API is a subset of the `moize` API.
154
155```javascript
156const memoized = nanomemoize(sum(a,b) => a + b);
157memoized(1,2); // 3
158memoized(1,2); // pulled from cache
159```
160
161`nanomemoize(function,options) returns function`
162
163The shape of options is:
164
165```javascript
166{
167 // only use the provided maxArgs for cache look-up, useful for ignoring final callback arguments
168 maxArgs: number,
169 // call last argument of memoized multi-args functions after a number of milliseconds via a timeout after the
170 // cached result has been returned, perhaps to ensure that callbacks are invoked, does not cache the timemout result
171 // e.g. nanomemoize(function(a,b,callback) { var result = a + b; callback(result); return result; },{maxArgs:2,callTimeout:0});
172 callTimeout: number,
173 // number of milliseconds to cache a result, set to `Infinity` or `-1` to never create timers or expire
174 maxAge: number,
175 // the serializer/key generator to use for single argument functions (optional, not recommended)
176 // must be able to serialize objects and functions, by default a Map is used internally without serializing
177 serializer: function,
178 // the equals function to use for multi-argument functions (optional, try to avoid) e.g. deepEquals for objects
179 equals: function,
180 // forces the use of multi-argument paradigm, auto set if function has a spread argument or uses `arguments` in its body.
181 vargs: boolean
182}
183```
184
185The returned function will also have these methods:
186
187`.clear()` clears the cache for the function.
188
189`.keys()` returns an array of arrays with each array being the arguments provided on a call of the function.
190
191`.values()` returns an array of arrays with each array being the results of a function call with the same index position as the keys.
192
193
194# Release History (reverse chronological order)
195
1962022-02-02 v3.0.3 Added unit test for `maxAge`. Adjusted varArg unit tests for more accuracy. Slight optimizations to multi argument memoized functions. Slight improvement to cache clearing that may reduce GC. Updated license file for copyright period. Updated docs on `callTimeout` for clarity.
197
1982022-02-01 v3.0.2 Fixed https://github.com/anywhichway/nano-memoize/issues/52 with custom equals functions not consistently working. `fast-equals` or `lodash.isEqual` now work. Slight performance degradation, but still generally the fastest.
199
2002022-01-29 v3.0.1 Fixed build issue where root index.js was not getting updated.
201
2022022-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.
203
2042022-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.
205
2062022-10-20 v1.3.1 Bumping version for https://github.com/anywhichway/nano-memoize/pull/41
207
2082022-03-30 v1.3.0 Dropped support for `dist` and `browser` directories.
209
2102022-03-15 v1.2.2 Bumped minor version for TS typings and some package dependency updates.
211
2122020-11-02 v1.2.1 Added main: "index.js" reference in package.json.
213
2142020-06-18 v1.2.0 Enhanced multi-arg handling so that arg lengths must match precisely (thanks @amazingmarvin), unless `maxArgs` is passed as an option.
215Also added `callTimeout` to go ahead and call underlying function to ensure callbacks are invoked if necessary.
216
2172020-05-26 v1.1.11 [Fixed Issue 17]Fixed https://github.com/anywhichway/nano-memoize/issues/17. It is not known when this bug made its way into the code.
218
2192020-02-30 v1.1.10 Moved growl to dev dependency.
220
2212020-01-30 v1.1.9 Code style improvements.
222
2232019-11-29 v1.1.8 Corrected typos in documentation.
224
2252019-09-25 v1.1.7 Manually created an IE 11 compatible version by removing arrow functions and replacing Object.assign
226with a custom function. Minor size increase from 660 to 780 Brotli bytes. Also eliminated complex `bind` approach in
227favor of closures. The latest v8 engine handles closures as fast as bound arguments for our case and we are not as
228concerned with older browser performace (particularly given how fast the code is anyway). Converted for loops to run in
229reverse, which for our case is faster (but is not always guranteed to be faster).
230
2312019-09-17 v1.1.6 Added a manually transpiled es5_ie11.html file with an Object.assign polyfill to the test directory to verify
232compatibility with IE11. Modified unit tests so they are ES5 compatible. All tests pass. Added `sideEffects=false` to package.json.
233
2342019-06-28 v1.1.5 Improved documentation. Updated version of `micro-memoize` used for benchmark testing. No code changes.
235
2362019-05-31 v1.1.4 [Fixed Issue 7](https://github.com/anywhichway/nano-memoize/issues/7).
237
2382019-04-09 v1.1.3 [Fixed Issue 6](https://github.com/anywhichway/nano-memoize/issues/6). Minor speed and size improvements.
239
2402019-04-02 v1.1.2 Speed improvements for multiple arguments. Now consistently faster than `fast-memoize` and `nano-memoize` across multiple test runs. Benchmarks run in a new test environment. The benchmarks for v1.1.1 although correct from a relative perspective, grossly understated actual performance due to a corrupt testing environment.
241
2422019-03-25 v1.1.1 Pushed incorrect version with v1.1.0. This corrects the version push.
243
2442019-03-25 v1.1.0 Added use of `WeakMap` for high-speed caching of single argument functions when passed objects. The `serializer` option no longer defaults to `(value) => JSON.stringify(value)` so if you want to treat objects that have the same string representation as the same, you will have to provide a `serializer`.
245
2462019-03-24 v1.0.8 Updated/corrected documentation.
247
2482019-03-24 v1.0.7 Made smaller and faster. Renamed `sngl` to `sng` and `mltpl` to `mlt`. Converted all functions to arrow functions except `sng` and `mlt`. Simplified and optimized `mlt`. Removed `()` around args to single argument arrow function definitions, e.g. `(a) => ...` became `a => ...`. Replaced the arg signature `()` in arrow functions with `_`, which is shorter. Eliminated multiple character variables except for those used in options to request memoization. Collapsed `setTimeout` into a single location. Defined `const I = Infinity`. Eliminated `()` around `? :` condition expressions. Changed `{}` to `Object.create(null)`. Documented all variables. Moved some variables around for clarity. Moved `options` into a destructing argument.
249
2502019-03-20 v1.0.6 Updated documentation.
251
2522019-03-11 v1.0.5 Now supports setting `maxAge` to Infinity and no timers will be created to expire caches.
253
2542019-02-26 v1.0.4 Further optimized cache expiration. See [Issue 4](https://github.com/anywhichway/nano-memoize/issues/4)
255
2562019-02-16 v1.0.3 Fixed README formatting
257
2582019-02-16 v1.0.2 Further optimizations to deal with [Issue 4](https://github.com/anywhichway/nano-memoize/issues/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.
259
2602019-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.
261
2622018-04-13 v1.0.0 Code style improvements.
263
2642018-02-07 v0.1.2 Documentation updates
265
2662018-02-07 v0.1.1 Documentationand benchmark updates
267
2682018-02-01 v0.1.0 Documentation updates. 50 byte decrease.
269
2702018-01-27 v0.0.7b BETA Documentation updates.
271
2722018-01-27 v0.0.6b BETA Minor size and speed improvements.
273
2742018-01-27 v0.0.5b BETA Fixed edge case where multi-arg key may be shorter than current args.
275
2762018-01-27 v0.0.4b BETA Fixed benchmarks. Removed maxSize. More unit tests. Fixed maxAge.
277
2782018-01-27 v0.0.3b BETA More unit tests. Documentation. Benchmark code in repository not yet running.
279
2802018-01-24 v0.0.2a ALPHA Minor speed enhancements. Benchmark code in repository not yet running.
281
2822018=01-24 v0.0.1a ALPHA First public release. Benchmark code in repository not yet running.