GithubHelp home page GithubHelp logo

planttheidea / micro-memoize Goto Github PK

View Code? Open in Web Editor NEW
233.0 6.0 16.0 3.36 MB

A tiny, crazy fast memoization library for the 95% use-case

License: MIT License

JavaScript 21.43% TypeScript 78.57%
javscript memoization performance

micro-memoize's Introduction

micro-memoize

A tiny, crazy fast memoization library for the 95% use-case

Table of contents

Summary

As the author of moize, I created a consistently fast memoization library, but moize has a lot of features to satisfy a large number of edge cases. micro-memoize is a simpler approach, focusing on the core feature set with a much smaller footprint (~1.44kB minified+gzipped). Stripping out these edge cases also allows micro-memoize to be faster across the board than moize.

Importing

ESM in browsers:

import memoize from 'micro-memoize';

ESM in NodeJS:

import memoize from 'micro-memoize/mjs';

CommonJS:

const memoize = require('micro-memoize');

Usage

const assembleToObject = (one: string, two: string) => ({ one, two });

const memoized = memoize(assembleToObject);

console.log(memoized('one', 'two')); // {one: 'one', two: 'two'}
console.log(memoized('one', 'two')); // pulled from cache, {one: 'one', two: 'two'}

Types

If you need them, all types are available under the MicroMemoize namespace.

import { MicroMemoize } from 'micro-memoize';

Composition

Starting in 4.0.0, you can compose memoized functions if you want to have multiple types of memoized versions based on different options.

const simple = memoized(fn); // { maxSize: 1 }
const upToFive = memoized(simple, { maxSize: 5 }); // { maxSize: 5 }
const withCustomEquals = memoized(upToFive, { isEqual: deepEqual }); // { maxSize: 5, isEqual: deepEqual }

NOTE: The original function is the function used in the composition, the composition only applies to the options. In the example above, upToFive does not call simple, it calls fn.

Options

isEqual

function(object1: any, object2: any): boolean, defaults to isSameValueZero

Custom method to compare equality of keys, determining whether to pull from cache or not, by comparing each argument in order.

Common use-cases:

  • Deep equality comparison
  • Limiting the arguments compared
import { deepEqual } from 'fast-equals';

type ContrivedObject = {
  deep: string;
};

const deepObject = (object: {
  foo: ContrivedObject;
  bar: ContrivedObject;
}) => ({
  foo: object.foo,
  bar: object.bar,
});

const memoizedDeepObject = memoize(deepObject, { isEqual: deepEqual });

console.log(
  memoizedDeepObject({
    foo: {
      deep: 'foo',
    },
    bar: {
      deep: 'bar',
    },
    baz: {
      deep: 'baz',
    },
  }),
); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}}

console.log(
  memoizedDeepObject({
    foo: {
      deep: 'foo',
    },
    bar: {
      deep: 'bar',
    },
    baz: {
      deep: 'baz',
    },
  }),
); // pulled from cache

NOTE: The default method tests for SameValueZero equality, which is summarized as strictly equal while also considering NaN equal to NaN.

isMatchingKey

function(object1: any[], object2: any[]): boolean

Custom method to compare equality of keys, determining whether to pull from cache or not, by comparing the entire key.

Common use-cases:

  • Comparing the shape of the key
  • Matching on values regardless of order
  • Serialization of arguments
import { deepEqual } from 'fast-equals';

type ContrivedObject = { foo: string; bar: number };

const deepObject = (object: ContrivedObject) => ({
  foo: object.foo,
  bar: object.bar,
});

const memoizedShape = memoize(deepObject, {
  // receives the full key in cache and the full key of the most recent call
  isMatchingKey(key1, key2) {
    const object1 = key1[0];
    const object2 = key2[0];

    return (
      object1.hasOwnProperty('foo') &&
      object2.hasOwnProperty('foo') &&
      object1.bar === object2.bar
    );
  },
});

console.log(
  memoizedShape({
    foo: 'foo',
    bar: 123,
    baz: 'baz',
  }),
); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}}

console.log(
  memoizedShape({
    foo: 'not foo',
    bar: 123,
    baz: 'baz',
  }),
); // pulled from cache

isPromise

boolean, defaults to false

Identifies the value returned from the method as a Promise, which will result in one of two possible scenarios:

  • If the promise is resolved, it will fire the onCacheHit and onCacheChange options
  • If the promise is rejected, it will trigger auto-removal from cache
const fn = async (one: string, two: string) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error(JSON.stringify({ one, two })));
    }, 500);
  });
};

const memoized = memoize(fn, { isPromise: true });

memoized('one', 'two');

console.log(memoized.cache.snapshot.keys); // [['one', 'two']]
console.log(memoized.cache.snapshot.values); // [Promise]

setTimeout(() => {
  console.log(memoized.cache.snapshot.keys); // []
  console.log(memoized.cache.snapshot.values); // []
}, 1000);

NOTE: If you don't want rejections to auto-remove the entry from cache, set isPromise to false (or simply do not set it), but be aware this will also remove the cache listeners that fire on successful resolution.

maxSize

number, defaults to 1

The number of values to store in cache, based on a Least Recently Used basis. This operates the same as maxSize on moize.

const manyPossibleArgs = (one: string, two: string) => [one, two];

const memoized = memoize(manyPossibleArgs, { maxSize: 3 });

console.log(memoized('one', 'two')); // ['one', 'two']
console.log(memoized('two', 'three')); // ['two', 'three']
console.log(memoized('three', 'four')); // ['three', 'four']

console.log(memoized('one', 'two')); // pulled from cache
console.log(memoized('two', 'three')); // pulled from cache
console.log(memoized('three', 'four')); // pulled from cache

console.log(memoized('four', 'five')); // ['four', 'five'], drops ['one', 'two'] from cache

onCacheAdd

function(cache: Cache, options: Options): void

Callback method that executes whenever the cache is added to. This is mainly to allow for higher-order caching managers that use micro-memoize to perform superset functionality on the cache object.

const fn = (one: string, two: string) => [one, two];

const memoized = memoize(fn, {
  maxSize: 2,
  onCacheAdd(cache, options) {
    console.log('cache has been added to: ', cache);
    console.log('memoized method has the following options applied: ', options);
  },
});

memoized('foo', 'bar'); // cache has been added to
memoized('foo', 'bar');
memoized('foo', 'bar');

memoized('bar', 'foo'); // cache has been added to
memoized('bar', 'foo');
memoized('bar', 'foo');

memoized('foo', 'bar');
memoized('foo', 'bar');
memoized('foo', 'bar');

NOTE: This method is not executed when the cache is manually manipulated, only when changed via calling the memoized method.

onCacheChange

function(cache: Cache, options: Options): void

Callback method that executes whenever the cache is added to or the order is updated. This is mainly to allow for higher-order caching managers that use micro-memoize to perform superset functionality on the cache object.

const fn = (one: string, two: string) => [one, two];

const memoized = memoize(fn, {
  maxSize: 2,
  onCacheChange(cache, options) {
    console.log('cache has changed: ', cache);
    console.log('memoized method has the following options applied: ', options);
  },
});

memoized('foo', 'bar'); // cache has changed
memoized('foo', 'bar');
memoized('foo', 'bar');

memoized('bar', 'foo'); // cache has changed
memoized('bar', 'foo');
memoized('bar', 'foo');

memoized('foo', 'bar'); // cache has changed
memoized('foo', 'bar');
memoized('foo', 'bar');

NOTE: This method is not executed when the cache is manually manipulated, only when changed via calling the memoized method. When the execution of other cache listeners (onCacheAdd, onCacheHit) is applicable, this method will execute after those methods.

onCacheHit

function(cache: Cache, options: Options): void

Callback method that executes whenever the cache is hit, whether the order is updated or not. This is mainly to allow for higher-order caching managers that use micro-memoize to perform superset functionality on the cache object.

const fn = (one: string, two: string) => [one, two];

const memoized = memoize(fn, {
  maxSize: 2,
  onCacheHit(cache, options) {
    console.log('cache was hit: ', cache);
    console.log('memoized method has the following options applied: ', options);
  },
});

memoized('foo', 'bar');
memoized('foo', 'bar'); // cache was hit
memoized('foo', 'bar'); // cache was hit

memoized('bar', 'foo');
memoized('bar', 'foo'); // cache was hit
memoized('bar', 'foo'); // cache was hit

memoized('foo', 'bar'); // cache was hit
memoized('foo', 'bar'); // cache was hit
memoized('foo', 'bar'); // cache was hit

NOTE: This method is not executed when the cache is manually manipulated, only when changed via calling the memoized method.

transformKey

function(Array<any>): any

A method that allows you transform the key that is used for caching, if you want to use something other than the pure arguments.

const ignoreFunctionArgs = (one: string, two: () => {}) => [one, two];

const memoized = memoize(ignoreFunctionArgs, {
  transformKey: (args) => [JSON.stringify(args[0])],
});

console.log(memoized('one', () => {})); // ['one', () => {}]
console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}]

If your transformed keys require something other than SameValueZero equality, you can combine transformKey with isEqual for completely custom key creation and comparison.

const ignoreFunctionArg = (one: string, two: () => void) => [one, two];

const memoized = memoize(ignoreFunctionArg, {
  isMatchingKey: (key1, key2) => key1[0] === key2[0],
  // Cache based on the serialized first parameter
  transformKey: (args) => [JSON.stringify(args[0])],
});

console.log(memoized('one', () => {})); // ['one', () => {}]
console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}]

Additional properties

memoized.cache

Object

The cache object that is used internally. The shape of this structure:

{
  keys: any[][], // available as MicroMemoize.Key[]
  values: any[] // available as MicroMemoize.Value[]
}

The exposure of this object is to allow for manual manipulation of keys/values (injection, removal, expiration, etc).

const method = (one: string, two: string) => ({ one, two });

const memoized = memoize(method);

memoized.cache.keys.push(['one', 'two']);
memoized.cache.values.push('cached');

console.log(memoized('one', 'two')); // 'cached'

NOTE: moize offers a variety of convenience methods for this manual cache manipulation, and while micro-memoize allows all the same capabilities by exposing the cache, it does not provide any convenience methods.

memoized.cache.snapshot

Object

This is identical to the cache object referenced above, but it is a deep clone created at request, which will provide a persistent snapshot of the values at that time. This is useful when tracking the cache changes over time, as the cache object is mutated internally for performance reasons.

memoized.fn

function

The original function passed to be memoized.

memoized.isMemoized

boolean

Hard-coded to true when the function is memoized. This is useful for introspection, to identify if a method has been memoized or not.

memoized.options

Object

The options passed when creating the memoized method.

Benchmarks

All values provided are the number of operations per second (ops/sec) calculated by the Benchmark suite. Note that underscore, lodash, and ramda do not support mulitple-parameter memoization (which is where micro-memoize really shines), so they are not included in those benchmarks.

Benchmarks was performed on an i7 8-core Arch Linux laptop with 16GB of memory using NodeJS version 10.15.0. The default configuration of each library was tested with a fibonacci calculation based on the following parameters:

  • Single primitive = 35
  • Single object = {number: 35}
  • Multiple primitives = 35, true
  • Multiple objects = {number: 35}, {isComplete: true}

NOTE: Not all libraries tested support multiple parameters out of the box, but support the ability to pass a custom resolver. Because these often need to resolve to a string value, a common suggestion is to just JSON.stringify the arguments, so that is what is used when needed.

Single parameter (primitive only)

This is usually what benchmarks target for ... its the least-likely use-case, but the easiest to optimize, often at the expense of more common use-cases.

Operations / second
fast-memoize 59,069,204
micro-memoize 48,267,295
lru-memoize 46,781,143
Addy Osmani 32,372,414
lodash 29,297,916
ramda 25,054,838
mem 24,848,072
underscore 24,847,818
memoizee 18,272,987
memoizerific 7,302,835

Single parameter (complex object)

This is what most memoization libraries target as the primary use-case, as it removes the complexities of multiple arguments but allows for usage with one to many values.

Operations / second
micro-memoize 40,360,621
lodash 30,862,028
lru-memoize 25,740,572
memoizee 12,058,375
memoizerific 6,854,855
ramda 2,287,030
underscore 2,270,574
Addy Osmani 2,076,031
mem 2,001,984
fast-memoize 1,591,019

Multiple parameters (primitives only)

This is a very common use-case for function calls, but can be more difficult to optimize because you need to account for multiple possibilities ... did the number of arguments change, are there default arguments, etc.

Operations / second
micro-memoize 33,546,353
lru-memoize 20,884,669
memoizee 7,831,161
Addy Osmani 6,447,448
memoizerific 5,587,779
mem 2,620,943
underscore 1,617,687
ramda 1,569,167
lodash 1,512,515
fast-memoize 1,376,665

Multiple parameters (complex objects)

This is the most robust use-case, with the same complexities as multiple primitives but managing bulkier objects with additional edge scenarios (destructured with defaults, for example).

Operations / second
micro-memoize 34,857,438
lru-memoize 20,838,330
memoizee 7,820,066
memoizerific 5,761,357
mem 1,184,550
ramda 1,034,937
underscore 1,021,480
Addy Osmani 1,014,642
lodash 1,014,060
fast-memoize 949,213

Browser support

  • Chrome (all versions)
  • Firefox (all versions)
  • Edge (all versions)
  • Opera 15+
  • IE 9+
  • Safari 6+
  • iOS 8+
  • Android 4+

Node support

  • 4+

Development

Standard stuff, clone the repo and npm install dependencies. The npm scripts available:

  • build => run webpack to build development dist file with NODE_ENV=development
  • build:minifed => run webpack to build production dist file with NODE_ENV=production
  • dev => run webpack dev server to run example app (playground!)
  • dist => runs build and build-minified
  • lint => run ESLint against all files in the src folder
  • prepublish => runs compile-for-publish
  • prepublish:compile => run lint, test, transpile:es, transpile:lib, dist
  • test => run AVA test functions with NODE_ENV=test
  • test:coverage => run test but with nyc for coverage checker
  • test:watch => run test, but with persistent watcher
  • transpile:lib => run babel against all files in src to create files in lib
  • transpile:es => run babel against all files in src to create files in es, preserving ES2015 modules (for pkg.module)

micro-memoize's People

Contributors

crecket avatar dependabot[bot] avatar inokawa avatar jcranendonk avatar planttheidea avatar rtorr avatar settingdust avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

micro-memoize's Issues

transformKey() typings

I copied and pasted the example code from the README:

const ignoreFunctionArgs = (one: string, two: () => {}) => [one, two];

const memoized = memoize(ignoreFunctionArgs, {
  isEqual(key1: string, key2: string) {
    return key1.args === key2.args;
  },
  transformKey(args: any[]) {
    return {
      args: JSON.stringify(args)
    };
  }
});

However, I get TypeScript errors:

Type '{ (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (string | number)[], space?: string | number): string; }' is not assignable to type 'KeyTransformer'.
  Type 'string' is not assignable to type 'Key'.

The second example also has type errors:

const ignoreFunctionArgs = (one: string, two: () => {}) => [one, two];

const memoized = memoize(ignoreFunctionArgs, {
  isEqual(key1: string, key2: string) {
    return key1.args === key2.args;
  },
  transformKey(args: any[]) {
    return {
      args: JSON.stringify(args)
    };
  }
});

Which errors out with:

Type '(args: any[]) => { args: string; }' is not assignable to type 'KeyTransformer'.
  Type '{ args: string; }' is missing the following properties from type 'any[]': length, pop, push, concat, and 28 more.

Type errors

Hello!

"micro-memoize": "^4.0.6"

I have a bunch of type errors related with micro-memoize:

ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(33,7):
TS2322: Type '(keyToMatch: any[]) => number' is not assignable to type 'KeyIndexGetter'.
  Types of parameters 'keyToMatch' and 'keyToMatch' are incompatible.
    Type 'RawKey' is not assignable to type 'any[]'.
      Type 'IArguments' is missing the following properties from type 'any[]': pop, push, concat, join, and 24 more.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(34,16):
TS2532: Object is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(35,7):
TS2322: Type '(keyToMatch: any[]) => number' is not assignable to type 'KeyIndexGetter'.
  Types of parameters 'keyToMatch' and 'keyToMatch' are incompatible.
    Type 'RawKey' is not assignable to type 'any[]'.
      Type 'IArguments' is not assignable to type 'any[]'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(37,7):
TS2322: Type '(keyToMatch: any[]) => 0 | -1' is not assignable to type 'KeyIndexGetter'.
  Types of parameters 'keyToMatch' and 'keyToMatch' are incompatible.
    Type 'RawKey' is not assignable to type 'any[]'.
      Type 'IArguments' is not assignable to type 'any[]'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(79,9):
TS2532: Object is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(79,9):
TS2722: Cannot invoke an object which is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(83,9):
TS2532: Object is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(85,13):
TS2722: Cannot invoke an object which is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(125,16):
TS2722: Cannot invoke an object which is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(165,12):
TS2722: Cannot invoke an object which is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(204,33):
TS2532: Object is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(206,7):
TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(206,21):
TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(228,11):
TS2722: Cannot invoke an object which is possibly 'undefined'.
ERROR in D:/Tripment/code/http-services-with-general-components/node_modules/micro-memoize/src/Cache.ts(232,11):
TS2722: Cannot invoke an object which is possibly 'undefined'.
Version: typescript 3.4.5, tslint 5.16.0

tsconfig

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "lib": ["dom", "es2017"],
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,

    /* Additional Checks */
    "noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,

    /* Debugging Options */
    "traceResolution": false /* Report module resolution log messages. */,
    "listEmittedFiles": false /* Print names of generated files part of the compilation. */,
    "listFiles": false /* Print names of files part of the compilation. */,
    "pretty": true /* Stylize errors and messages using color and context. */,

    /* Experimental Options */
    // "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
    // "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,

    "jsx": "preserve"
  },
  "compileOnSave": false,
  "exclude": ["node_modules/**/*"]
}

Add git tags

Could you please add git tags on new releases? This will automatically create GitHub releases, which can help users getting notified on new releases via RSS.

Thanks for this project!

Snapshot results

Is there a way to snapshot results so that memoized output is not affected by changes?

const memoize = require('micro-memoize');

const assembleToObject = (one, two) => ({ one, two });

const memoized = memoize(assembleToObject);

console.log(memoized('one', 'two')); 
console.log(memoized('one', 'two')); 
memoized('one', 'two').one = 'changed';
console.log(memoized('one', 'two')); 

This prints:

{ one: 'one', two: 'two' }
{ one: 'one', two: 'two' }
{ one: 'changed', two: 'two' }

I want the code above always return{ one, two }

Importing micro-memoize from a Typescript NodeJS environment

Getting this error with the recommended import from tsc --build
import memoize from "micro-memoize/mjs";

error TS2307: Cannot find module 'micro-memoize/mjs' or its corresponding type declarations.

1 import memoize from "micro-memoize/mjs";
                      ~~~~~~~~~~~~~~~~~~~

It looks like the types are bundled with Node in the mjs folder. The types are packaged with the root library. Is there something I'm missing or a way for me to fix this import?

"Failed to parse source map" errors

When using micro-memoize version 4.0.10 in a react application, starting the application in development mode is giving the following warnings:

Failed to parse source map from '/home/user/Projects/cra-app/node_modules/src/Cache.ts' file: Error: ENOENT: no such file or directory, open '/home/user/Projects/cra-app/node_modules/src/Cache.ts'                                                            
                                             
Failed to parse source map from '/home/user/Projects/cra-app/node_modules/src/index.ts' file: Error: ENOENT: no such file or directory, open '/home/user/Projects/cra-app/node_modules/src/index.ts'                                                                                  
                                                                                         
Failed to parse source map from '/home/user/Projects/cra-app/node_modules/src/utils.ts' file: Error: ENOENT: no such file or directory, open '/home/user/Projects/cra-app/node_modules/src/utils.ts'

which then leads to some warning in following lines in the console.

Indeed, after looking at the contents of the .map files in the package of version 4.0.10 the files are referencing two paths up, which leads to trying to look at a path outside the package:

$ cat node_modules/micro-memoize/dist/micro-memoize.js.map
{"version":3,"file":"micro-memoize.js","sources":["../../src/utils.ts","../../src/Cache.ts","../../src/index.ts"],"sourcesContent":[null,null,null],"names":[],"mapping
[...truncated...]

This is happening with latest version 4.0.10. Probably, somehow, the source map files were badly generated because the previous patch version 4.0.9 does not generate these warnings. I have reverted as a workaround.

No memoization for asynchronous function with no inputs

I am using micro-memoize to skip doing work in the future calls for some async functions. However, the function runs again in the subsequent calls.

I cannot reproduce it in a simple example like the following,

import memoize from 'micro-memoize';

function sleep(n) {
  return new Promise(resolve => setTimeout(resolve, n));
}

async function doSomething_raw() {
  console.log("running...")
  await sleep(1000)
  return "hey"
}
const doSomething = memoize(doSomething_raw, { isPromise: true })


await doSomething()
await doSomething()

But in the complex project, I am seeing the function running two times:
https://github.com/aminya/setup-cpp/blob/771f77f24f8e63f91c375b6bba0f861ca7ea16c8/src/utils/setup/setupPipPack.ts#L86-L93

https://github.com/aminya/setup-cpp/actions/runs/6114633731/job/16596651001?pr=198#step:8:2476
https://github.com/aminya/setup-cpp/actions/runs/6114633731/job/16596651001?pr=198#step:8:3043

One of the differences is that there are nested memorized async functions in the complex function.

Advice on reseting the cache

Hi again and thanks for this amazing lib!

I'm having trouble with my unit tests in which the memoized wrongly share results between unrelated tests 😅. (would not happen in real execution, by design)

The easy solution is to reset the cache between each test with beforeEach

However I'm not sure how I should be reseting the cache.

Would this reliably work?

memoized.cache = {
  keys: [[]],
  values: [],
}

micro-memoize dependecy 4.0.12 cause TS errors

Hi,
I just today installed new project without npm lockfile and building failed for moize with TypeScript errors

`node_modules/.pnpm/[email protected]/node_modules/moize/index.d.ts:16:21 - error TS2314: Generic type 'Cache' requires 1 type argument(s).

16 export type Cache = MicroMemoize.Cache;
~~~~~~~~~~~~~~~~~~
node_modules/.pnpm/[email protected]/node_modules/moize/index.d.ts:17:35 - error TS2314: Generic type 'Options' requires 1 type argument(s).

17 export type MicroMemoizeOptions = MicroMemoize.Options;`

I dug deeper as we use moize without problems elsewhere and found out that in that new generated lock file peer dependency micro-memoize is resolved with version 4.0.12 which is 5 days old new version in NPM a there were changes in typings files which cause these errors.

So I went with workaround and edited manually our lock file to use again 4.0.11 and it works.

Could this be fixed so we do not need to manually update lockfiles? Thank You!

[question] how to auto-clear memoization-cache every 20 minutes?

Hello,

For a long-running web-sevice, I'd like async data to be auto-removed from the memoization-cache every 20 minutes. Is there a micro-memoize formula solution to this problem?

I've been using micro-memoize for a year or two now and its been great. Thank you for any response you may have.

The benchmarks are utterly broken and always have been

I wanted to test by own memoizing library against other ones to compare my speed and I wanted to try out your benchmarks. All the functions which you are testing are incorrect. You are using fibonacci functions which call themselves and are later memoized, but the non-memoized versions are called. You didn't notice because all your benchmarks are with input 35 which is low enough for the slowdown not to show.

const fib = n => n < 2 ? n : fib(n -1) + fib(n - 2)
const memo = mMemo(fib)

As you can clearly see - fib is calling fib, not mMemo. You don't have memoization at all.

const fib = mMemo(n => n < 2 ? n : fib(n -1) + fib(n - 2))

That is the correct way.

Support of TS 4.1 with noUncheckedIndexedAccess

Hi there,

I have similar problem as #37
TS 4.1 introduced new compilerOption noUncheckedIndexedAccess. see:
https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess

When I use TS 4.1 or above with this option, micro-memoize fails to compile.

To reproduce bug, create a project with TS 4.1 or above, turn on noUncheckedIndexedAccess, import and use micro-memoize and run a TS build. I see:

tsc --noEmit

node_modules/micro-memoize/src/Cache.ts:82:23 - error TS2345: Argument of type 'Key | undefined' is not assignable to parameter of type 'Key'.
  Type 'undefined' is not assignable to type 'any[]'.

82     if (isMatchingKey(keys[0], keyToMatch)) {
                         ~~~~~~~

node_modules/micro-memoize/src/Cache.ts:88:27 - error TS2345: Argument of type 'Key | undefined' is not assignable to parameter of type 'Key'.
  Type 'undefined' is not assignable to type 'any[]'.

88         if (isMatchingKey(keys[index], keyToMatch)) {
                             ~~~~~~~~~~~

node_modules/micro-memoize/src/Cache.ts:176:13 - error TS2339: Property 'length' does not exist on type 'Key | undefined'.

176     const { length } = existingKey;
                ~~~~~~

node_modules/micro-memoize/src/Cache.ts:186:22 - error TS2532: Object is possibly 'undefined'.

186         if (!isEqual(existingKey[index], keyToMatch[index])) {
                         ~~~~~~~~~~~

node_modules/micro-memoize/src/Cache.ts:194:20 - error TS2532: Object is possibly 'undefined'.

194     return isEqual(existingKey[0], keyToMatch[0]) ? 0 : -1;
                       ~~~~~~~~~~~

node_modules/micro-memoize/src/Cache.ts:220:7 - error TS2322: Type 'Key | undefined' is not assignable to type 'Key'.
  Type 'undefined' is not assignable to type 'any[]'.

220       keys[index + 1] = keys[index];
          ~~~~~~~~~~~~~~~

node_modules/micro-memoize/src/Cache.ts:269:43 - error TS2345: Argument of type 'Key | undefined' is not assignable to parameter of type 'RawKey'.
  Type 'undefined' is not assignable to type 'RawKey'.

269         const keyIndex = this.getKeyIndex(firstKey);
                                              ~~~~~~~~


Found 7 errors in the same file, starting at: node_modules/micro-memoize/src/Cache.ts:82

Function signatures are lost when memoized in version 3

Hi there! It seems that in version 3, memoized functions do not keep their type signatures. Can we fix support for this? I checked the type definitions and this can probably be done with:

export default function memoize<T extends Function>(
  fn: T | MicroMemoize.Memoized,
  options?: MicroMemoize.Options,
): T

Or:

export default function memoize<T extends Function>(
  fn: T | MicroMemoize.Memoized,
  options?: MicroMemoize.Options,
): T & MicroMemoize.Memoized;

Infinite caching?

Hi and thanks for the great lib! Greatly boosted my app which is built around immutability but has expensive computations.

How do we get an infinite caching? maxSize: Number.POSITIVE_INFINITY ?

Import error for common js compiler module type

I get this error when trying to execute jest unit tests.

 TypeError: (0 , micro_memoize_1.default) is not a function

Import syntax used in codebase

import memoize from 'micro-memoize';

Typescript compiler configured to use CommonJs module for unit tests. I looked what is defined here

image

And seems export for cjs file is defined correctly.

I have created a simple repo to reproduce an error: https://github.com/r0ss0neri/memoise-import-example

steps are simple:

  • clone and install deps
  • just run app.component.spec

Thanks for advice.

Remove memcache tags

This library incorrectly defines npm tags for memcache and memcached and should be removed, as I can not find any evidence of an integration to memcache.

It is misleading for people looking for memcache libraries to get this result which solves an entirely different problem.

Mixture of deep and shallow arguments

I didn't see any obvious way to handle a case like the following.

const foo = (options, a, b) => { ... }

Here, you'd want options to use deep equality, but a and b to compare identities.

Is there any convenient way to do this with micro-memoize?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.