{"id":26307187,"url":"https://github.com/sindresorhus/mem","last_synced_at":"2025-03-15T10:01:53.961Z","repository":{"id":44967149,"uuid":"48387914","full_name":"sindresorhus/memoize","owner":"sindresorhus","description":"Memoize functions - an optimization technique used to speed up consecutive function calls by caching the result of calls with identical input","archived":false,"fork":false,"pushed_at":"2024-08-13T12:02:40.000Z","size":94,"stargazers_count":1085,"open_issues_count":5,"forks_count":53,"subscribers_count":15,"default_branch":"main","last_synced_at":"2024-10-29T15:34:46.826Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sindresorhus.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/security.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"sindresorhus","open_collective":"sindresorhus","buy_me_a_coffee":"sindresorhus","custom":"https://sindresorhus.com/donate"}},"created_at":"2015-12-21T18:38:11.000Z","updated_at":"2024-10-29T01:07:07.000Z","dependencies_parsed_at":"2022-09-05T17:00:24.693Z","dependency_job_id":"7a9b830f-e8d1-4972-947b-cdba7d6c3966","html_url":"https://github.com/sindresorhus/memoize","commit_stats":{"total_commits":93,"total_committers":18,"mean_commits":5.166666666666667,"dds":0.4731182795698925,"last_synced_commit":"ff0f5391a1dfdb3996cceec15a5815360d4952a8"},"previous_names":["sindresorhus/memoize","sindresorhus/mem"],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fmemoize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fmemoize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fmemoize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fmemoize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sindresorhus","download_url":"https://codeload.github.com/sindresorhus/memoize/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243713402,"owners_count":20335567,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-15T10:01:40.716Z","updated_at":"2025-03-15T10:01:53.951Z","avatar_url":"https://github.com/sindresorhus.png","language":"TypeScript","readme":"# memoize\n\n\u003e [Memoize](https://en.wikipedia.org/wiki/Memoization) functions - An optimization used to speed up consecutive function calls by caching the result of calls with identical input\n\nMemory is automatically released when an item expires or the cache is cleared.\n\n\u003c!-- Please keep this section in sync with https://github.com/sindresorhus/p-memoize/blob/main/readme.md --\u003e\n\nBy default, **only the memoized function's first argument is considered** via strict equality comparison. If you need to cache multiple arguments or cache `object`s *by value*, have a look at alternative [caching strategies](#caching-strategy) below.\n\nIf you want to memoize Promise-returning functions (like `async` functions), you might be better served by [p-memoize](https://github.com/sindresorhus/p-memoize).\n\n## Install\n\n```sh\nnpm install memoize\n```\n\n## Usage\n\n```js\nimport memoize from 'memoize';\n\nlet index = 0;\nconst counter = () =\u003e ++index;\nconst memoized = memoize(counter);\n\nmemoized('foo');\n//=\u003e 1\n\n// Cached as it's the same argument\nmemoized('foo');\n//=\u003e 1\n\n// Not cached anymore as the argument changed\nmemoized('bar');\n//=\u003e 2\n\nmemoized('bar');\n//=\u003e 2\n\n// Only the first argument is considered by default\nmemoized('bar', 'foo');\n//=\u003e 2\n```\n\n##### Works well with Promise-returning functions\n\nBut you might want to use [p-memoize](https://github.com/sindresorhus/p-memoize) for more Promise-specific behaviors.\n\n```js\nimport memoize from 'memoize';\n\nlet index = 0;\nconst counter = async () =\u003e ++index;\nconst memoized = memoize(counter);\n\nconsole.log(await memoized());\n//=\u003e 1\n\n// The return value didn't increase as it's cached\nconsole.log(await memoized());\n//=\u003e 1\n```\n\n```js\nimport memoize from 'memoize';\nimport got from 'got';\nimport delay from 'delay';\n\nconst memoizedGot = memoize(got, {maxAge: 1000});\n\nawait memoizedGot('https://sindresorhus.com');\n\n// This call is cached\nawait memoizedGot('https://sindresorhus.com');\n\nawait delay(2000);\n\n// This call is not cached as the cache has expired\nawait memoizedGot('https://sindresorhus.com');\n```\n\n### Caching strategy\n\nBy default, only the first argument is compared via exact equality (`===`) to determine whether a call is identical.\n\n```js\nimport memoize from 'memoize';\n\nconst pow = memoize((a, b) =\u003e Math.pow(a, b));\n\npow(2, 2); // =\u003e 4, stored in cache with the key 2 (number)\npow(2, 3); // =\u003e 4, retrieved from cache at key 2 (number), it's wrong\n```\n\nYou will have to use the `cache` and `cacheKey` options appropriate to your function. In this specific case, the following could work:\n\n```js\nimport memoize from 'memoize';\n\nconst pow = memoize((a, b) =\u003e Math.pow(a, b), {\n  cacheKey: arguments_ =\u003e arguments_.join(',')\n});\n\npow(2, 2); // =\u003e 4, stored in cache with the key '2,2' (both arguments as one string)\npow(2, 3); // =\u003e 8, stored in cache with the key '2,3'\n```\n\nMore advanced examples follow.\n\n#### Example: Options-like argument\n\nIf your function accepts an object, it won't be memoized out of the box:\n\n```js\nimport memoize from 'memoize';\n\nconst heavyMemoizedOperation = memoize(heavyOperation);\n\nheavyMemoizedOperation({full: true}); // Stored in cache with the object as key\nheavyMemoizedOperation({full: true}); // Stored in cache with the object as key, again\n// The objects appear the same, but in JavaScript, they're different objects\n```\n\nYou might want to serialize or hash them, for example using `JSON.stringify` or something like [serialize-javascript](https://github.com/yahoo/serialize-javascript), which can also serialize `RegExp`, `Date` and so on.\n\n```js\nimport memoize from 'memoize';\n\nconst heavyMemoizedOperation = memoize(heavyOperation, {cacheKey: JSON.stringify});\n\nheavyMemoizedOperation({full: true}); // Stored in cache with the key '[{\"full\":true}]' (string)\nheavyMemoizedOperation({full: true}); // Retrieved from cache\n```\n\nThe same solution also works if it accepts multiple serializable objects:\n\n```js\nimport memoize from 'memoize';\n\nconst heavyMemoizedOperation = memoize(heavyOperation, {cacheKey: JSON.stringify});\n\nheavyMemoizedOperation('hello', {full: true}); // Stored in cache with the key '[\"hello\",{\"full\":true}]' (string)\nheavyMemoizedOperation('hello', {full: true}); // Retrieved from cache\n```\n\n#### Example: Multiple non-serializable arguments\n\nIf your function accepts multiple arguments that aren't supported by `JSON.stringify` (e.g. DOM elements and functions), you can instead extend the initial exact equality (`===`) to work on multiple arguments using [`many-keys-map`](https://github.com/fregante/many-keys-map):\n\n```js\nimport memoize from 'memoize';\nimport ManyKeysMap from 'many-keys-map';\n\nconst addListener = (emitter, eventName, listener) =\u003e emitter.on(eventName, listener);\n\nconst addOneListener = memoize(addListener, {\n\tcacheKey: arguments_ =\u003e arguments_, // Use *all* the arguments as key\n\tcache: new ManyKeysMap() // Correctly handles all the arguments for exact equality\n});\n\naddOneListener(header, 'click', console.log); // `addListener` is run, and it's cached with the `arguments` array as key\naddOneListener(header, 'click', console.log); // `addListener` is not run again because the arguments are the same\naddOneListener(mainContent, 'load', console.log); // `addListener` is run, and it's cached with the `arguments` array as key\n```\n\nBetter yet, if your function’s arguments are compatible with `WeakMap`, you should use [`deep-weak-map`](https://github.com/futpib/deep-weak-map) instead of `many-keys-map`. This will help avoid memory leaks.\n\n## API\n\n### memoize(fn, options?)\n\n#### fn\n\nType: `Function`\n\nThe function to be memoized.\n\n#### options\n\nType: `object`\n\n##### maxAge\n\nType: `number` | `Function`\\\nDefault: `Infinity`\\\nExample: `arguments_ =\u003e arguments_ \u003c new Date() ? Infinity : 60_000`\n\nMilliseconds until the cache entry expires.\n\nIf a function is provided, it receives the arguments and must return the max age.\n\n##### cacheKey\n\nType: `Function`\\\nDefault: `arguments_ =\u003e arguments_[0]`\\\nExample: `arguments_ =\u003e JSON.stringify(arguments_)`\n\nDetermines the cache key for storing the result based on the function arguments. By default, **only the first argument is considered**.\n\nA `cacheKey` function can return any type supported by `Map` (or whatever structure you use in the `cache` option).\n\nRefer to the [caching strategies](#caching-strategy) section for more information.\n\n##### cache\n\nType: `object`\\\nDefault: `new Map()`\n\nUse a different cache storage. Must implement the following methods: `.has(key)`, `.get(key)`, `.set(key, value)`, `.delete(key)`, and optionally `.clear()`. You could for example use a `WeakMap` instead or [`quick-lru`](https://github.com/sindresorhus/quick-lru) for a LRU cache.\n\nRefer to the [caching strategies](#caching-strategy) section for more information.\n\n### memoizeDecorator(options)\n\nReturns a [decorator](https://github.com/tc39/proposal-decorators) to memoize class methods or static class methods.\n\nNotes:\n\n- Only class methods and getters/setters can be memoized, not regular functions (they aren't part of the proposal);\n- Only [TypeScript’s decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#parameter-decorators) are supported, not [Babel’s](https://babeljs.io/docs/en/babel-plugin-proposal-decorators), which use a different version of the proposal;\n- Being an experimental feature, they need to be enabled with `--experimentalDecorators`; follow TypeScript’s docs.\n\n#### options\n\nType: `object`\n\nSame as options for `memoize()`.\n\n```ts\nimport {memoizeDecorator} from 'memoize';\n\nclass Example {\n\tindex = 0\n\n\t@memoizeDecorator()\n\tcounter() {\n\t\treturn ++this.index;\n\t}\n}\n\nclass ExampleWithOptions {\n\tindex = 0\n\n\t@memoizeDecorator({maxAge: 1000})\n\tcounter() {\n\t\treturn ++this.index;\n\t}\n}\n```\n\n### memoizeClear(fn)\n\nClear all cached data of a memoized function.\n\n#### fn\n\nType: `Function`\n\nThe memoized function.\n\n## Tips\n\n### Cache statistics\n\nIf you want to know how many times your cache had a hit or a miss, you can make use of [stats-map](https://github.com/SamVerschueren/stats-map) as a replacement for the default cache.\n\n#### Example\n\n```js\nimport memoize from 'memoize';\nimport StatsMap from 'stats-map';\nimport got from 'got';\n\nconst cache = new StatsMap();\nconst memoizedGot = memoize(got, {cache});\n\nawait memoizedGot('https://sindresorhus.com');\nawait memoizedGot('https://sindresorhus.com');\nawait memoizedGot('https://sindresorhus.com');\n\nconsole.log(cache.stats);\n//=\u003e {hits: 2, misses: 1}\n```\n\n## Related\n\n- [p-memoize](https://github.com/sindresorhus/p-memoize) - Memoize promise-returning \u0026 async functions\n","funding_links":["https://github.com/sponsors/sindresorhus","https://opencollective.com/sindresorhus","https://buymeacoffee.com/sindresorhus","https://sindresorhus.com/donate"],"categories":["包","Packages","Modules","模块","Miscellaneous","TypeScript","Number"],"sub_categories":["其他","Miscellaneous","Function","杂项","函数"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Fmem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsindresorhus%2Fmem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Fmem/lists"}